目录
1、Bean的生命周期 :
1、Spring对Bean进行实例化。
2、Spring将值和Bean的引用注入Bean对应的属性中。
3、如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()接口方法
4、如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()接口方法,将BeanFactory容器实例传入。
5、如果Bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext接口方法,将应用上下文的引用传入。
6、如果Bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()接口方法。
7、如果Bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()接口方法。类似地,如果Bean使用init-method声明了初始化方法,该方法也会被调用。
8、如果Bean实现了BeanPostProcessor接口,Spring将调用它们的post-PoressAfterInitialization()方法。
9、此时此刻,Bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到应用上下文被销毁。
10、如果Bean实现了DisposableBean接口,Spring将调用它的destory()接口方法。同样,如果Bean使用destory-method声明了销毁方法,该方法也会被调用。
2、自动化装配bean
Spring通过两个角度来实现自动化装配:
- 组件扫描(component scanning) :Spring会自动发现应用上下文中创建的bean。
- 自动装配(autowiring):Spring自动满足bean之间的依赖。
2.1 创建可被发现的bean:
@Component
public class SgtPeppers implements CompactDisc {
private String title = "Sgt.Peppers Lonely";
private String article = "The beatles";
public void play(){
System.out.println("Play" + title + "by" +article);
}
}
SgtPeppers类上使用了@Component注解,这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean。但是,组件扫描默认是不开启的,我们需要显式配置一下Spring,从而命令它去寻找带有@Caomponent注解的类,为其创建bean。
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
2.2 为组件扫描的Bean命名
@Component("lonelyHearts")
public class SgtPeppers implements CompactDisc {
}
另一种为bean命名的方式是使用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解来设置bean的ID。
2.3 设置组建扫描的基础包
@configuration
@ComponentScan(basePackages="soundsystem") //单个基础包
public class CDPlayerConfig {
}
@configuration
@ComponentScan(basePackages={"soundsystem", "video"}) //多个基础包
public class CDPlayerConfig {
}
以上的基础包是以String类型表示的,如果重构代码的话,所指的的基础包可能会出现错误。
我们可以用basePackageClasses替换basePackages,这是不再使用String类型的名称来指定包,为basePackageClasses属性所设置的数组里包含了类,这些类所在的包会成为组件扫描的基础包。
@configuration
@ComponentScan(basePackageClasses={"CDPlayer.class", "DVDPlayer.class"})
public class CDPlayerConfig {
}
2.4 为bean添加注解实现自动装配
自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。为了声明要进行自动装配,我们可以借助Spring的@autowired注解。
@autowired
public void setCompactDisc(CompactDisc cd){
this.cd = cd;
}
假如木有匹配的bean,那么应用上下文创建的时候,Spring会抛出一个异常。为了避免异常出现,可以将@autowired的required属性设置为false;这个时候,Spring自动装配没有匹配的bean的话,Spring会让这个bean处于未装配的状态。同时需要注意的是,代码如果没有非空检查的话,这个处于未装配状态的属性有可能出现NullpointerException。
@autowired(requied = false)
public void setCompactDisc(CompactDisc cd){
this.cd = cd;
}
/*@autowired可以替换为@Inject,后者来源于Java依赖注入规范*/
3、通过Java代码装配bean
3.1 声明简单的bean
@Bean //@Bean(name="lonnlyHearts")
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
3.2 借助JavaConfig实现注入
在JavaConfig中装配bean的最简单方式是引用创建bean的方法。
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
4、通过XML装配bean
4.1 创建XML配置规范
使用XML配置文件的方式装配bean,首要的就是要创建一个基于Spring配置规范的XML文件,该配置文件以<beans>为根元素(相当于Java配置的@Configuration注解),包含一个或多个<bean>元素(相当于配置类中@Bean注解)。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--configuration details go here-->
<bean class="spring.impl.BenzCar"></bean>
</beans>
4.2 声明一个简单的bean
<bean id="compactDisc" class="soundsystem.SgtPeppers" />
如果没有明确给定的ID,那么创建的bean的ID将会是“soundsystem.SgtPeppers#0”,其中“#0”为计数方式,用以区分相同类型的其他bean,如果声明了另一个 SgtPeppers,并且没有明确进行表识,那么它的ID为 “soundsystem.SgtPeppers#1”。
4.3 借助构造器注入初始化bean
SpringXML的配置中,只有一种声明bean的方式:使用<bean>元素指定class的属性。但是,在XML中声明DI时,会有多种可选方案,具体到构造器注入,有两种基本的配置方案:
- <construction-arg>元素
- 使用Spring 3.0所以入的 c- 命名空间
4.3.1 构造器注入bean引用
第二种需要在 c- 命名空间和模式声明之后使用。
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc" />
</bean>
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:cd-ref="compacctDisc" />
下图描述了这个属性名是如何组合而成的。
属性名以 “c:” 开头,也就是命名空间的前缀。接下来是要装配的构造器参数名,在此之后是 “-ref” ,这是一个命名的约定,它会告诉Spring正在装配一个bean的引用,这个引用的名字是 compactDisc,而不是字面量 “compactDisc”。
4.3.2 将字面量注入到构造器中
目前为止,我们所做的都是类型的装配——也就是将对象的引用装配到依赖它们的其他对象中,而有时我们需要一个字面量值来配置对象。
<bean id="compactDisc"
class="soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely" />
<constructor-arg value="The Beatles" />
</bean>
<bean id="compactDisc"
class="soundsystem.BlankDisc">
<c:_0="Sgt. Pepper's Lonely" />
<c:_1="The Beatles" />
</bean>
4.3.3 装配集合
4.4 设置属性
作为一个通用规则,对强依赖使用构造器注入,对可选性的依赖使用属性注入。
<bean id="cdPlayer"
class="soundsystem.CDPlayer" >
<property name="compactDisc" ref="compactDisc" />
</bean>
<bean id="cdPlayer"
class="soundsystem.CDPlayer"
p:compactDisc-ref="compactDisc" />
<property>元素为属性的 Setter 方法所提供的功能与<constructor-arg>元素为构造器所提供的功能是一样的。
第二种为 p- 命名空间,启用它的方式和 c- 命名空间一样。
将字面量注入到属性中与构造器参数非常类似,可以参照上方代码,不再赘述 。
5、导入混合配置
在Spring中,这些配置方案都不是互斥的。关于混合配置,必须要知道的事情就是在自动装配时,它不在意装配的 bean 来自那里。
5.1 在JavaConfig中引用XML配置
@Configuration //CDPlayerConfig.class
public class CDPlayerCong {
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
<bean id="compactDisc" //cd-config.xml
class="soundsystem.BlankDisc"
c:_0="Sgt. Pepper's Lonely"
c:_1="The Beatles" >
<constructor-arg>
<list>
<value>Sgt. Pepper's Lonely </value>
<value>Lucy in the Sky with Diamonds </value>
<value>Getting Better </value>
<!-- ...other tracks omitted for brevity... -->
</list>
<constructor-arg>
</bean>
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {
}
两个bean——配置在JavaConfig中的CDPlayer以及配置在XML中的BlankDisc——都会被加载到Spring容器之中。因为CDPlayer中带有@Bean注解的方法接受一个CompactDisc作为参数,因此BlankDisc将会装配进来,此时与它是通过XML配置的没有任何关系。
5.2 在XML中引用JavaConfig
同理,如果我们将BlankDisc配置在JavaConfig中,CDPlayer配置在XML中,那么我们需要用<bean>元素将Java配置导入到XML配置中。注:<import>元素只能导入到其他的XML配置文件,并没有XML元素能够导入JavaConfig类。
...
<bean class="soundsystem.CDConfig" />
<import resource="cdplayer-config.xml" />
</bean>
小结:
对于Spring配置bean的三种方式,推荐尽可能使用自动化配置,以避免显示配置带来的维护成本。如果确实需要显式配置Spring的话,应该优先选择基于Java的配置,它比基于XML的配置更加强大、类型安全并且易于重构。