第二章:装配Bean
本章内容:
- 声明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
package com.kotobuki2.soundsys;
/**
* @author [email protected]
* @since 2018/11/17 下午7:21
*/
public interface CompactDisc {
void play();
}
package com.kotobuki2.soundsys;
import org.springframework.stereotype.Component;
/**
* @author [email protected]
* @since 2018/11/17 下午7:22
*/
@Component
public class SgtPeppers implements CompactDisc {
private String title = "SgtPeppers title";
private String artiest = "The Beatles";
@Override
public void play() {
System.out.println("playing..");
}
}
package com.kotobuki2.soundsys;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author [email protected]
* @since 2018/11/17 下午7:24
*/
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
通过XML配置开启注解扫描:
<context:component-scan base-package="soundsys"/>
自动装配测试:
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;
/**
* @author [email protected]
* @since 2018/11/17 下午7:28
*/
@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的别名:
@Component("alias")
2.2.3 设置组件扫描的基础包
默认以配置类所在的包为基础包进行扫描。
自定义扫描包:
@Configuration
@ComponentScan("package-name")
//扫描多个基础包
@ComponentScan(basePackages = {"package1", "package2"})
但是用直接指定包名会出现问题:包名被变更以后便无法扫描到所需要的类,因此,还有另一种指定扫描包的方法:
@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})
这种方式下,这些类所在的包都会作为基础包进行扫描,即便代码重构也不会受到影响。
2.2.4 通过为bean添加注解实现自动装配
package com.kotobuki2.soundsys;
/**
* @author [email protected]
* @since 2018/11/17 下午8:51
*/
public interface MediaPlayer {
void play();
}
package com.kotobuki2.soundsys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author [email protected]
* @since 2018/11/17 下午8:50
*/
@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:
@Bean(name="alias")
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
借助JavaConfig实现注入:
@Bean
public CDPlayer cdPlayer(){
return CDPlayer(new sgtPeppers());
}
@Bean
public CDPlayer cdPlayer(CompactDisc disc){
return new CDplayer(disc);
}
后者不要求disc必须在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者XML来进行配置。
通过构造器注入:
@Bean
public CDPlayer cdPlayer(CompactDisc disc){
CDPlayer cdPlayer = new CDPlayer(disc);
cdPlayer.setCompactDisc(disc);
return cdPlayer;
}
2.4 通过XML装配Bean
在XML配置中,需要创建一个以
可以借助Spring Tool Suite创建和管理Spring XML配置文件。
2.4.1 声明一个简单的bean:
<bean id="bean_id" class="com.soundsys.SgtPeppers" />
如果没有指明id,bean将会根据类全限定名指定,为了减少XML配置的繁琐,只需要对需要按名称引用的bean进行命名。“com.soundsys.SgtPeppers#0”…
<bean id="cdPlayer" class="com.soundsys.CDPlayer">
<constructor-arg ref="compactDisc" />
</bean>
2.4.2 c命名空间
2.4.3 将字面量注入到构造器中:
<bean id="compactDisc" class="com.soundsys.BlackDisc">
<constructor-arg value="title" />
<constructor-arg value="The Beatles" />
</bean>
使用 value 属性,将给定的值注入到构造器中。
2.4.3 装配集合
<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>
或者
<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命名空间
2.4.5 导入混合配置
在 JavaConfig 中引用 JavaConfig 配置:
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc disc) {
return new CDPlayer(disc);
}
}
或者:
@Configuration
@Import(CDPlayerConfig.class, CDConfig.class)
public class SoundSysConfig {
}
新建一个配置类,使用@Import导入两个配置类。
在JavaConfig中引入XML配置:
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSysConfig {
}
在XML配置中引用XML配置:
<beans>
<import resource="cd-config.xml"/>
<bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc">
</beans>
在XML中引入JavaConfig配置:
<beans>
<bean class="com.soundsys.CDConfig"/>
<bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc"/>
</beans>
或者:
<beans>
<bean class="com.soundsys.CDConfig"/>
<import resource="cdplayer-config.xml"/>
</beans>
新建一个配置文件,分别导入JavaConfig配置和XML配置。
小结
Spring框架的核心是Spring容器,负责管理应用中组件的生命周期,它会创建这些组件并保证它们的依赖能够得到满足。
尽可能使用自动配置,以避免显式配置带来的维护成本。
如果确实需要显式配置,应优先选择基于Java的配置,因为其更加强大、类型安全且易于重构。