装配:创建应用对象之间协作关系的行为。
Spring 提供了三种主要的装配机制:
- 在 XML 中进行显式配置
- 在 Java 中进行显式配置
- 隐式的 bean 发现机制和自动装配
装配方案选择:尽可能地使用自动配置的机制;当必须要显式配置 bean 的时候,推荐使用类型安全并且比 XML 更加强大的 JavaConfig;只有当想要利用便利的 XML 命名空间,并且在 JavaConfig 中没有同样的实现时,才应该使用 XML。
自动化装配 Bean
Spring 从两个角度来实现自动化装配:
- 组件扫描:Spring 会自动发现应用上下文中所创建的 bean
- 自动装配:Spring 自动满足 bean 之间的依赖
实现流程:
- 创建类并将其标记为使用 Spring 容器管理。示例代码:
1 2 3 4 5
| package wiki.hlj.ch2;
public interface Sport { void run(); }
|
1 2 3 4 5 6 7 8 9 10 11 12
| package wiki.hlj.ch2; import org.springframework.stereotype.Component;
@Component public class Hurdle implements Sport { public void run() { int amount = 10; String name = "Bill"; System.out.println(name + " crossed " + amount + " hurdles in a minute."); }
}
|
- 启用组件扫描,可以使用 @ComponentScan 注解或者使用 XML (<context:component-scan>)。示例代码:
1 2 3 4 5 6 7 8 9 10 11
| package wiki.hlj.ch2;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;
@Configuration @ComponentScan(basePackages = {"wiki.hlj.ch2"}) public class SportConfig { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package wiki.hlj.ch2.test;
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import wiki.hlj.ch2.Sport; import wiki.hlj.ch2.SportConfig;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SportConfig.class) public class SportTest {
@Autowired private Sport sport;
@Test public void testRun() { sport.run(); }
}
|
也可以使用 Java 依赖注入规范中所提供的 @Named 注解来为 bean 设置 ID,但这种方式不推荐
@Inject 注解来源于 Java 依赖注入规范,在大多数场景下,它可以和 @Autowired 互相替换,并
@Autowired 注解可以用在类的任何方法上
通过 Java 代码装配 bean
JavaConfig 是配置代码,它不应该包含任何业务逻辑,也不应该侵入到业务逻辑代码之中,通常会将 JavaConfig 放到单独的包中,使它与其他的应用程序逻辑分离开来。
实现流程:创建配置类 -> 声明简单的 bean -> 借助 JavaConfig 实现注入
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package wiki.hlj.ch2;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class CDPlayerConfig {
@Bean(name = "sgtPeppers") public CompactDisc sgtPeppers() { return new SgtPeppers(); }
@Bean public CDPlayer cdPlayer() { return new CDPlayer(sgtPeppers()); }
@Bean public CDPlayer anotherCdPlayer() { return new CDPlayer(sgtPeppers()); }
@Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(compactDisc); } }
|
1 2 3 4 5 6 7
| package wiki.hlj.ch2;
public interface MediaPlayer {
void play();
}
|
1 2 3 4 5 6 7
| package wiki.hlj.ch2;
public interface CompactDisc {
void play();
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package wiki.hlj.ch2;
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band"; private String artist = "The Beatles";
public void play() { System.out.println("Playing " + title + " by " + artist); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package wiki.hlj.ch2; import org.springframework.beans.factory.annotation.Autowired;
public class CDPlayer implements MediaPlayer { private CompactDisc cd;
@Autowired public CDPlayer(CompactDisc cd) { this.cd = cd; }
public void play() { cd.play(); }
}
|
通过 XML 装配 bean
使用 bean 元素,示例<bean id="sayHello" class="wiki.hlj.ch1.SayHello" />
借助构造器注入初始化 bean,两种方案:
设置属性:
<property> 元素;p- 命名空间
混合配置
@Import 注解
假设 AConfig 中装载了类 A,BConfig 中装载了类 B,同时类 B 依赖于类 A,则可在类 B 类声明上方使用注解 @Import(AConfig.class);或者创建一个更高级别的 SummaryConfig ,在这个类中使用 @Import 将两个配置组合在一起:@Import(AConfig.lass, BConfig.class)
@ImportResource 注解
通过它可实现在 JavaConfig 中引用基于 XML 的配置
在 XML 中,可以使用 <import> 元素来拆分 XML 配置,实现在一个 XML 配置中引用另一个 XML 配置