本章内容
- 声明 bean
- 构造器注入和 Setter 方法注入
- 装配 bean
- 控制 bean 的创建和销毁
Spring 配置的可选方案
当描述 bean 如何进行装配时, Spring 具有非常大的灵活性,它提供了三种主要的装配机制:
- 在 XML 中进行显示配置。
- 在 Java中进行显示配置。
- 隐式的 bean 发现机制和自动装配。
Tips: 根据需要使用一种,或搭配使用。
当必须要显示配置 bean 的时候推荐使用类型安全的 JavaConfig。
当想要使用便利的 XML 命名空间,并且在 JavaConfig 没有同样实现时,使用 XML。
自动化装配 bean
Spring 从两个角度来实现自动化装配:
- 组件扫描( component scanning ): Spring 会自动发现应用上下文中所创建的 bean 。
- 自动装配( autowiring ): Spring 自动满足 bean 之间的依赖。
@Component
public class SgtPeppers{
//........
}
@Component 注解表明该类会作为组件类,并告知 Spring 要为这个类创建 bean 。
但是 Spring 默认不启用组件扫描,所以需要我们显示的配置。
Java 类的方法
示例:
@Configuration
@ComponentScan
public class CDPlayerConfig{
}
类 CDPlayerConfig 通过 Java 代码定义了 Spring 的装配股则。如果没有其他配置, @ComponentScan 默认会扫描与配置类相同的包以及这个包下的所有子包,查找带有 @Component 注解的类,并为其创建一个 bean 。
XML 的方式
使用 XML 启用组件扫描,可以使用 Spring context 命名空间的 元素。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package=""></context:component-scan>
</beans>
为组件扫描的 bean 命名
Spring 应用上下文中所有的 bean 都会给定一个 ID 。对于没有明确配置 ID 的 bean , Spring 会根据类名为其指定。规则为——将类名的第一个字母变为小写。
如何给指定的 ID
我们所要做的就是将期望的 ID 作为值传递给 @Component 注解。
示例:
@Component("lonelyHeartsClub")
public class SgtPeppers {
}
设置组件扫描的基础包
对于之前的 @ComponentScan 我们没有设置任何属性。这意味着,按照默认规则,它会以配置类所在的包作为基础包( base package )来扫描左键。但是,当我们想要把配置类放在单独的包中,使其与其他的应用代码区分开来,我们应该怎么做?
要满足这样的需求,需要做的就是在 @ComponentScan 的 value 属性中指明包的名称:
@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig{
}
也可以明确的表明设置的是基础包,可以通过 basePackages 属性进行配置:
@Configuration
@ComponentScan(basePackages="soundsystem")
public class CDPlayerConfig{
}
如果想设置多个基础包,只需将 basePackages 属性设置为一个数组即可:
@Configuration
@ComponentScan(basePackages={"soundsystem", "video"})
public class CDPlayerConfig{
}
因为所设置的基础包是以 String 类型表示的,是可行的,但这种方法是类型不安全( not type-safe )的。当重构代码可能会出现错误。
@ComponentScan 还提供了另一种方法,那就是将其指定为包中所含的类或借口。
@Configuration
@ComponentScan(basePackageClasses={CDplayer.class, DVDPlayer.class}
public class CDPalyerConfig{
}
Tips: 可以考虑在包中创建一个用来进行扫描的空标记借口( marker interface )。
通过为 bean 添加注解实现自动装配
自动装配就是让 Spring 自动满足 bean 依赖的一种方法,在满足依赖的过程中,会在 Spring 应用上下文中寻找匹配某个 bean 需求的其他 bean 。为了声明要进行自动装配,我们可以借助 Spring 的 @Autowired 注解。
@Component
public class CDPlayer{
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd){
this.cd = cd ;
}
}
@Autowired 注解不仅能够用在构造器上,还能用在属性的 Setter 方法上。实际上,@Autowired注解可以用在类的任何方法上。发挥完全相同的作用:
@Autowired
public void insertDisc(CompactDisc cd){
this.cd = cd;
}
不管是什么方法, Spring 都会尝试满足方法参数上所声明的依赖。假如有且只有一个 bean 匹配依赖需求,则装配这个 bean 。
另外,如若将 required 属性设置为 false 时,没有匹配的 bean 会处于未装配的状态,不进行 null 检查的话,可能会出现 NullPointerException 。
通过 Java 代码装配 bean
当想要使用第三方库中的组件装配到你的应用中,没有办法添加 @Component 和 @Autowired 注解,必须要采用显示装配的方式。
JavaConfig 在概念上,它与应用程序中的业务逻辑和领域代码不同,不应该包含任何业务逻辑,也不应该侵入到业务逻辑代码中,通常会将 JavaConfig 放到单独的包中,与其他应用程序逻辑分离开来。
Java 的方式
@Configuration
public class CDPlayerConfig{
}
@Configuration 注解表明这个类是一个配置类,该类包含在 Spring 应用上下文中如何创建 bean 的细节。
可以同时使用组件扫描和显示配置。
声明简单的 bean
@Bean(name="lonelyHeartsClubBand")
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}
@Bean 注解告诉 Spring 这个方法会返回一个对象,并要注册为 Spring 应用上下文中的 bean 。默认情况下,bean 的 ID 与注解的方法名是一样的,也可通过 name 属性来设置。
借助 JavaConfig 实现注入
@Bean
public CDPlayer cdPalyer(){
return new CDPlayer(sgtPeppers());
}
public CDPlayer cdPlayer(){
return new CDPlayer(sgtPeppers());
}
使用带参构造器构建实例,而且因为 sgtPeppers() 添加了注解,Spring 拦截所有对它的调用,并确保直接返回该方法所创建的 bean ,而不是每次都对其进行实际的调用 。默认情况下,bean 都是单例的,所以两个 CDplayer bean 会得到相同的 sgtPeppers 实例。
另一种易于理解的方式:
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc);
}
当 Spring 调用 cdPlayer() 创建 CDPlayer bean 的时候,它会自动装配一个 CompactDisc 到配置方法中。然后,方法体按照合适的方法来使用它。
通过这种方式是最佳选择,不用要求声明到同一个配置类中。甚至可以是通过组件扫描自动发现或者通过 XML 来进行配置。
以上都是使用构造器实现的 DI 功能,但是我们完全可以采用其他的 DI 配置。
@Bean
public CDPlayer cdPlayer(Disc disc) {
CDPlayer cdPlayer = new CDPlayer();
cdPlayer.setDics(disc);
return cdPlayer;
}
带有 @Bean 注解的方法可以采用任何必要的 Java 功能来产生 bean 实例。
创建 XML 配置规范
借助构造器注入初始化 bean
- constructor-arg 元素
- 使用 Spring 3.0 所引入的c - 命名空间
<bean id="cdPlayer" class="soundsystem.CDplayer">
<constructor-arg ref="compactDisc" />
</bean>
替代方案:
<bean id="cdPalyer" class="soundsystem.CDplayer"
c:cd-ref="compactDisc" />
以上使用了构造器参数的名称。在优化构建过程,将调试标志移除掉,这种方式可能无法正常执行。
使用位置信息的方案:
<bean id="cdPalyer" class="soundsystem.CDplayer"
c:_0-ref="compactDisc" />
参数名称换成了参数索引,因为 XML 不允许数字作为属性的第一个字符,因此必须添加一个下划线作为前缀。
当只有一个构造器的时候,可以不用去标示参数:
<bean id="cdPalyer" class="soundsystem.CDplayer"
c:_-ref="compactDisc" />
将字面量注入到构造器中:
<bean id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="Sgt.Peppers" />
<constructor-arg value="The Beatles:" />
</bean>
<bean id="compactDisc2"
class="soundsystem.BlankDisc"
c:_0="Sgt.Peppers"
c:_1="The Beatles:" />
装配集合:
<bean id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg>
<list>
<value>Sgt.Peppers</value>
<value>lucy in the sky</value>
</list>
</constructor-arg>
</bean>
设置属性
强依赖选择构造器注入,可选性依赖使用属性注入。
<bean id="cdPalyer"
class="soundsystem.CDPlyaer">
<property name="compactDisc" ref="compactDisc" />
<property name="cdname" value="cdname" />
<property name="tracks">
<list>
<value>Sgt.Peppers</value>
<value>With a Little</value>
</list>
</property>
</bean>
相应的可以使用 p- 命名空间
<bean id="cdPlayer"
class="soundsystem.CDPlayer"
p:compactDisc-ref="compactDisc"
p:cdname="cdname" />
另外也可以借助 util- 命名空来所提供的 util:list 元素,来创建一个列表的 bean 。将其声明到单独的 bean 之中。
<util:list id="trackList">
<value>Sgt.Peppers</value>
<value>With a Little Help from </value>
<value>Fixing a Hole</value>
</util:list>
导入和混合配置
在 JavaConfig 中组合
两个配置类使用 @Import 组合
//在其中之一引入另一个
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig{
//......
}
//创建一个更高级别的类
@Configuration
@import({CDPlayer.class, CDConfig.class})
public class SoundSystemConfg{
}
配置类和 XML 组合
使用 @ImportResource(“path”)
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig{
}
在 XML 配置中组合
在 XML 配置文件中导入 Java 配置
<bean class="soundsystem.CDConfig" />
在 XML 中导入 XML
<import resource="conf.xml" />