前言:Spring可以管理singleton作用域的Bean的生命周期,Spring可以精确知道该Bean何时被创建、何时被初始化完成、容器何时准备销毁该Bean实例。Spring管理Bean的生命周期行为主要有两个时机,一是注入依赖关系之后,二是即将销毁Bean之前。(本篇主要针对ApplicationContext容器进行展开)
本篇文章重点关注以下问题:
- 引言;
- Spring容器中各级别的生命周期接口及方法;
- 演示Spring Bean的生命周期。
0. 引言
1. Spring容器中各级别的生命周期接口及方法
我们将Spring容器中Bean的生命周期级别分为四级,分别是:Bean自身方法、Bean级生命周期接口方法、容器级生命周期接口方法、工厂后处理器接口方法。
1. Bean自身的方法,包括:
* Bean本身调用的方法
* 通过配置文件中的init-method和destroy-method指定的方法;
2. Bean级生命周期接口方法,包括:
* InitializingBean接口
* DiposableBean接口
* BeanNameAware接口
* ApplicationContextAware接口
* BeanFactoryAware接口
* 其他
3. 容器级生命周期接口方法,包括:
* InstantiationAwareBeanPostProcessor接口实现
* BeanPostProcessor 接口实现
* 一般称它们的实现类为“后处理器”
4. 工厂级生命周期口方法(BeanFactoryPostProcessor接口的实现类)
* AspectJWeavingEnabler
* ConfigurationClassPostProcessor
* CustomAutowireConfigurer等
* 工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
2. Bean自身方法及Bean级生命周期方法
Bean自身的方法:调用构造函数实例化bean,调用setter设置属性,调用init-method,destroy-method。
1. init-method :指定某个方法在Bean实例化完成,依赖关系设置结束后执行;
2. destroy-method :指定某个方法在Bean销毁之前被执行。
1. InitializingBean接口 :指定某个方法在Bean实例化完成,依赖关系设置结束后执行;(init-method之前执行)
2. DiposableBean接口 :指定某个方法在Bean销毁之前被执行。(destory-method之前执行)
3. ApplicationContextAware接口 :在实例化Bean时,为Bean注入ApplicationContext
4. BeanNameAware接口 :在实例化Bean时,为Bean注入beanName
下面的Person类中定义了Bean自身方法以及Bean级生命周期方法,便于最后进行测试,以观察Person实例的整个生命周期变化。
package com.wj.chapter5.life.all;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
*
* Bean自身方法
* * Bean本身调用的方法
* * init-method
* * destroy-method
*
* Bean级生命周期接口:
* * BeanNameAware : 在实例化Bean时,为Bean注入beanName
* * ApplicationContextAware : 在实例化Bean时,为Bean注入ApplicationContext
* * InitializingBean : 在实例化Bean之前,进行初始化操作
* * DisposableBean : 在销毁Bean之前,进行析构操作
* @author Administrator
*
*/
public class Person implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean {
private String name;
private String address;
private int phone;
private ApplicationContext applicationContext;
private String beanName;
public Person() {
System.out.println("【Person】【构造器】");
}
/*********************************** Bean自身方法begin. ************************************/
// 通过<bean>的init-method属性指定的初始化方法
public void myInit() {
System.out.println("【Bean自身方法】【init-method】初始化方法...");
}
// 通过<bean>的destroy-method属性指定的初始化方法
public void myDestory() {
System.out.println("【Bean自身方法】【destroy-method】销毁方法...");
}
public void sayHello() {
System.out.println("【Bean自身方法】sayHello...");
}
/*********************************** Bean级生命接口方法begin. ************************************/
public void setName(String name) {
this.name = name;
System.out.println("【Bean级接口】【注入属性】注入属性name...");
}
public void setAddress(String address) {
this.address = address;
System.out.println("【Bean级接口】【注入属性】注入属性address...");
}
public void setPhone(int phone) {
this.phone = phone;
System.out.println("【Bean级接口】【注入属性】注入属性phone...");
}
// 这是BeanFactoryAware接口方法
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("【Bean级接口】【ApplicationContextAware接口】注入Spring容器ApplicationContext...");
}
// 这是BeanNameAware接口方法
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
System.out.println("【Bean级接口】【BeanNameAware接口】注入beanName...");
}
// 这是InitializingBean接口方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("【Bean级接口】【InitializingBean接口】初始化方法...");
}
// 这是DiposibleBean接口方法
@Override
public void destroy() throws Exception {
System.out.println("【DiposibleBean接口】销毁方法...");
}
@Override
public String toString() {
return "Person [name=" + name + ", address=" + address + ", phone=" + phone + ", applicationContext=" + applicationContext + ", beanName=" + beanName + "]";
}
}
3. 容器级生命周期接口方法
容器级生命周期接口方法:有InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现,一般称他们的实现类为后处理器。实现类独立于bean,以容器附加装置的形式注册到spring当中。当spring创建任何bean时,这些后处理器都会发生作用,所以后处理器的影响是全局性的。当然,用户可以通过合理的编写后处理器,让其仅对感兴趣的bean进行加工处理。
Bean级生命接口和容器级生命接口是个性和共性辩证统一思想的体现。前者解决bean的个性化处理的问题,后者解决容器中某些bean共性化处理的问题。
1. InstantiationAwareBeanPostProcessor接口:此接口可以在Bean实例化前、Bean实例化后分别进行操作,也可以对Bean实例化之后进行属性操作;(为BeanPostProcessor的子接口)
2. BeanPostProcessor接口:此接口的方法可以对Bean的属性进行更改。
下面分别实现两种容器级接口,首先是InstantiationAwareBeanPostProcessor接口:
package com.wj.chapter5.life.all;
import java.beans.PropertyDescriptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
/**
* 容器级生命周期接口:
* InstantiationAwareBeanPostProcessor 接口本质是BeanPostProcessor的子接口,
* 一般我们继承Spring为其提供的适配器类,InstantiationAwareBeanPostProcessorAdapter来使用它,
* 此接口可以在Bean实例化前、Bean实例化后分别进行操作,也可以对Bean实例化之后进行属性操作
*/
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
public MyInstantiationAwareBeanPostProcessor() {
super();
System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】【构造器】");
}
// 实例化Bean之前调用
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】实例化Bean之前调用");
return null;
}
// 实例化Bean之后调用
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】实例化Bean之后调用");
return true;
}
// 初始化Bean之前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】初始化Bean之前调用");
return bean;
}
// 初始化Bean之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】初始化Bean之后调用");
return bean;
}
// 设置某个属性时调用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
String beanName) throws BeansException {
System.out.println("【容器级接口】【InstantiationAwareBeanPostProcessor实现类】实例化Bean之后,设置某个属性时调用");
return pvs;
}
}
然后实现BeanPostProcessor接口:
package com.wj.chapter5.life.all;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* 容器级生命周期接口:
* 此接口的方法可以对Bean的属性进行更改
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("【容器级接口】【MyBeanPostProcessor实现类】【构造器】");
}
// 初始化Bean之前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【容器级接口】【BeanPostProcessor实现类】初始化Bean之前调用");
return bean;
}
// 初始化Bean之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【容器级接口】【BeanPostProcessor实现类】初始化Bean之后调用");
return bean;
}
}
注意:InstantiationAwareBeanPostProcessor接口实际上是BeanPostProcessor的子接口,所以实际开发中用InstantiationAwareBeanPostProcessor接口的适配器类InstantiationAwareBeanPostProcessorAdapter即可。
4. 工厂级生命周期方法
工厂级生命周期接口方法(BeanFactoryPostProcessor接口的实现类):
package com.wj.chapter5.life.all;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* 工厂级接口(此接口可用于重写或添加bean的属性值,甚至可以立即初始化Bean)
*
* BeanFactoryPostProcessor可以对bean的定义(配置元数据)进行处理。
* 也就是说,Spring IoC容器允许BeanFactoryPostProcessor
* 在容器实际实例化任何其它的bean之前读取配置元数据,并有可能修改它。
* 如果你愿意,你可以配置多个BeanFactoryPostProcessor。
* 你还能通过设置'order'属性来控制BeanFactoryPostProcessor的执行次序。
*/
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
super();
System.out.println("【工厂级接口】【BeanFactoryPostProcessor实现类】【构造器】");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
System.out.println("【工厂级接口】【BeanFactoryPostProcessor实现类】Spring容器加载之后,所有Bean实例化之前调用");
// 重写Person Bean的phone属性
BeanDefinition bd = arg0.getBeanDefinition("person");
bd.getPropertyValues().addPropertyValue("phone", "110");
}
}
5. XML配置信息
<?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-4.3.xsd"> <!-- 定义工厂级生命周期接口. --> <bean id="beanFactoryPostProcessor" class="com.wj.chapter5.life.all.MyBeanFactoryPostProcessor"></bean> <!-- 定义容器级生命周期接口. --> <bean id="beanPostProcessor" class="com.wj.chapter5.life.all.MyBeanPostProcessor"></bean> <bean id="instantiationAwareBeanPostProcessor" class="com.wj.chapter5.life.all.MyInstantiationAwareBeanPostProcessor"></bean> <!-- 定义Bean自身及Bean级生命周期接口. --> <bean id="person" class="com.wj.chapter5.life.all.Person" init-method="myInit" destroy-method="myDestory" scope="singleton"> <property name="name" value="熊燕子"></property> <property name="address" value="南京"></property> <property name="phone" value="60110"></property> </bean> </beans>
6. 测试代码
package com.wj.chapter5.life.all;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain {
private static final String PATH_XML = "com/wj/chapter5/life/all/applicationContext-all.xml";
public static void main(String[] args) {
System.out.println("============================== 现在开始初始化容器. ==============================");
ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext(PATH_XML);
System.out.println("\r\n============================== 容器初始化成功. ==============================");
//得到Preson,并使用
Person person = factory.getBean("person",Person.class);
person.sayHello();
System.out.println(person);
System.out.println("\r\n============================== 现在开始关闭容器! ==============================");
factory.close();
}
}
运行结果为:
分析上述运行结果,可以发现Person Bean的实例化过程如下:
1. 准备Spring容器
* 实例化BeanFactoryPostProcessor实现类;
* 执行BeanFactoryPostProcessor的postProcessBeanFactory修改XML对Bean配置的元信息;
2. 实例化Bean
* 实例化BeanPostProcessor实现类
* 实例化InstantiationAwareBeanPostProcessorAdapter实现类
* InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法,Bean实例化之前调用此方法
* 调用Person构造器进行初始化
* InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法,Bean实例化之后调用此方法
* InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法,可以修改Bean的属性信息(读取BeanFactoryPostProcessor的postProcessBeanFactory方法中修改的XML对Bean的配置的元信息,修改Bean的属性)
3. 注入依赖关系
* 注入属性:name、address、phone
* 注入BeanName
* 注入ApplicationContext
4. 初始化Bean
* BeanPostProcessor实现类调用接口方法postProcessBeforeInitialization对属性进行更改
* InstantiationAwareBeanPostProcessor调用postProcessBeforeInitialization方法,初始化Bean之前调用
* InitializingBean实现类调用afterPropertiesSet()进行Bean的初始化方法
* 调用<bean>的init-method属性指定的初始化方法
* BeanPostProcessor实现类接口方法postProcessAfterInitialization对属性进行更改
* InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法,初始化Bean之后调用
*
5. 使用Bean
* 调用sayHello()方法
* 打印Person信息(可以发现舒心phone已改为110,和配置文件中不同)
6. 销毁Bean
* 调用DiposibleBean接口的destory方法
* 调用<bean>的destroy-method属性指定的销毁方法
7. 小结
通过实现bean生命周期接口对bean进行额外的控制,虽然让bean具有了更细致的生命周期阶段,但也带来了一个问题:Bean和Spring框架紧密绑定在一起了,这和spring“不对应用程序类作任何限制”的理论是相悖的。因此我们推荐业务类完全POJO化,只实现自己的业务接口,不需要和某个特定框架的接口相关联。
可通过<bean>的init-method和destroy-method属性配置方式为bean指定初始化和销毁的方法,采用这种方式的效果和通过实现InitializingBean,DisposableBean接口所达到的效果是完全相同的,但是采用前者配置方式可以使bean不需要和特定的spring接口绑定。
对于ApplicationContextAware和BeanNameAware接口,第一个接口让bean感知容器(即ApplicationContext实例,从而以此获取该容器配置的其他bean对象),而后者让bean获得配置文件中对应的配置名称。在一般情况下用户不需要关心这两个接口。如果bean希望获得容器中的其他bean,可以通过属性注入的方式引用这些bean。如果bean希望在运行期获知在配置文件中的Bean名称,可以简单的将名称作为属性注入。
综上所述,我们认为除非编写一个基于spring之上的扩展框架插件或者子项目之类的东西,否则用户完全可以抛开以上4个bean生命周期的接口类。
但BeanPostProcessor接口却不一样,它不要求bean去继承它,它可以完全像插件一样注册到spring容器中,为容器提供额外的功能。spring充分利用了BeanPostProcessor对bean进行加工处理(SpringAOP以此为基础)
代码下载地址链接:http://pan.baidu.com/s/1gf3mQUR 密码:utv9