本章内容:
- 声明bean
- 构造器注入和Setter方法注入
- 装配bean
- 控制bean的创建和销毁
在Spring中,对象无需自己查找或创建与其所关联的对象,容器负责把需要相互协作的对象引用赋值给各个对象,这种协作关系成为装配。
2.1 Spring配置的可选方案
Spring容器负责创建应用程序中的bean并通过DI来协调对象之间的关系。开发人员需要做的是告诉Spring需要创建哪些对象并且如何装配在一起。
Spring提供了三种可选方式:
- XML配置
- Java显式配置
- 隐式的bean发现机制和自动装配
如何选择:尽可能使用自动配置机制,当必须显式配置时使用JavaConfig,当JavaConfig中没有同样实现时使用XML配置。
2.2 自动化装配bean
2.2.1 创建可被发现的bean
1 2 3 4 5 6 7 8 9 10
| package com.kotobuki2.soundsys;
public interface CompactDisc { void play(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.kotobuki2.soundsys;
import org.springframework.stereotype.Component;
@Component public class SgtPeppers implements CompactDisc { private String title = "SgtPeppers title"; private String artiest = "The Beatles";
@Override public void play() { System.out.println("playing.."); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.kotobuki2.soundsys;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;
@Configuration @ComponentScan public class CDPlayerConfig { }
|
通过XML配置开启注解扫描:
1
| <context:component-scan base-package="soundsys"/>
|
自动装配测试:
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
| package com.test;
import com.kotobuki2.soundsys.CDPlayerConfig; import com.kotobuki2.soundsys.CompactDisc; 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 static org.junit.Assert.assertNotNull;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = CDPlayerConfig.class) public class CDPlayerTest { @Autowired private CompactDisc compactDisc;
@Test public void cdTest() { assertNotNull(compactDisc); } }
|
2.2.2 为组件扫描的bean命名
默认将类名第一个字母小写后的字符串作为bean的id。
可以通过注解标示bean的别名:
2.2.3 设置组件扫描的基础包
默认以配置类所在的包为基础包进行扫描。
自定义扫描包:
1 2 3 4
| @Configuration @ComponentScan("package-name")
@ComponentScan(basePackages = {"package1", "package2"})
|
但是用直接指定包名会出现问题:包名被变更以后便无法扫描到所需要的类,因此,还有另一种指定扫描包的方法:
1 2
| @Configuration @ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})
|
这种方式下,这些类所在的包都会作为基础包进行扫描,即便代码重构也不会受到影响。
2.2.4 通过为bean添加注解实现自动装配
1 2 3 4 5 6 7 8 9 10
| package com.kotobuki2.soundsys;
public interface MediaPlayer { void play(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.kotobuki2.soundsys;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;
@Component public class CDPlayer implements MediaPlayer { private CompactDisc compactDisc;
@Autowired public CDPlayer(CompactDisc compactDisc) { this.compactDisc = compactDisc; }
@Override public void play() { compactDisc.play(); } }
|
@Autowired注解不仅能够用在构造器上,也能用在属性的Setter方法上。
2.3 通过Java装配bean
在进行显式配置的时候,JavaConfig是更好的方案,因为其强大、类型安全并且重构友好。因为其本身就是Java代码。
声明简单的bean:
1 2 3 4
| @Bean(name="alias") public CompactDisc sgtPeppers() { return new SgtPeppers(); }
|
借助JavaConfig实现注入:
1 2 3 4 5 6 7 8 9
| @Bean public CDPlayer cdPlayer(){ return CDPlayer(new sgtPeppers()); }
@Bean public CDPlayer cdPlayer(CompactDisc disc){ return new CDplayer(disc); }
|
后者不要求disc必须在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者XML来进行配置。
通过构造器注入:
1 2 3 4 5 6
| @Bean public CDPlayer cdPlayer(CompactDisc disc){ CDPlayer cdPlayer = new CDPlayer(disc); cdPlayer.setCompactDisc(disc); return cdPlayer; }
|
2.4 通过XML装配Bean
在XML配置中,需要创建一个以作为根元素的XML配置文件。
可以借助Spring Tool Suite创建和管理Spring XML配置文件。
2.4.1 声明一个简单的bean:
1
| <bean id="bean_id" class="com.soundsys.SgtPeppers" />
|
如果没有指明id,bean将会根据类全限定名指定,为了减少XML配置的繁琐,只需要对需要按名称引用的bean进行命名。“com.soundsys.SgtPeppers#0”…
元素:
1 2 3
| <bean id="cdPlayer" class="com.soundsys.CDPlayer"> <constructor-arg ref="compactDisc" /> </bean>
|
2.4.2 c命名空间
p命名空间和c命名空间
2.4.3 将字面量注入到构造器中:
1 2 3 4
| <bean id="compactDisc" class="com.soundsys.BlackDisc"> <constructor-arg value="title" /> <constructor-arg value="The Beatles" /> </bean>
|
使用 value 属性,将给定的值注入到构造器中。
2.4.3 装配集合
1 2 3 4 5 6 7 8 9 10
| <bean id="beat" class="com.soundsys.beat"> <constructor-arg value="The Beatles"/> <constructor-arg> <list> <ref bean="bean1"/> <ref bean="bean2"/> <ref bean="bean3"/> </list> </constructor-arg> </bean>
|
或者
1 2 3 4 5 6 7 8 9
| <bean id="beat" class="com.soundsys.beat"> <constructor-arg value="The Beatles"/> <constructor-arg> <set> <value>SgtPeppers</value> <value>The Beatles</value> </set> </constructor-arg> </bean>
|
使用两者的区别就是 list 和 set 会忽略重复元素。
2.4.4 p命名空间
p命名空间和c命名空间
2.4.5 导入混合配置
在 JavaConfig 中引用 JavaConfig 配置:
1 2 3 4 5 6 7 8
| @Configuration @Import(CDConfig.class) public class CDPlayerConfig { @Bean public CDPlayer cdPlayer(CompactDisc disc) { return new CDPlayer(disc); } }
|
或者:
1 2 3 4
| @Configuration @Import(CDPlayerConfig.class, CDConfig.class) public class SoundSysConfig { }
|
新建一个配置类,使用@Import导入两个配置类。
在JavaConfig中引入XML配置:
1 2 3 4 5
| @Configuration @Import(CDPlayerConfig.class) @ImportResource("classpath:cd-config.xml") public class SoundSysConfig { }
|
在XML配置中引用XML配置:
1 2 3 4
| <beans> <import resource="cd-config.xml"/> <bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc"> </beans>
|
在XML中引入JavaConfig配置:
1 2 3 4
| <beans> <bean class="com.soundsys.CDConfig"/> <bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc"/> </beans>
|
或者:
1 2 3 4
| <beans> <bean class="com.soundsys.CDConfig"/> <import resource="cdplayer-config.xml"/> </beans>
|
新建一个配置文件,分别导入JavaConfig配置和XML配置。
小结
Spring框架的核心是Spring容器,负责管理应用中组件的生命周期,它会创建这些组件并保证它们的依赖能够得到满足。
尽可能使用自动配置,以避免显式配置带来的维护成本。
如果确实需要显式配置,应优先选择基于Java的配置,因为其更加强大、类型安全且易于重构。