所有的事物,都会有自己的生老病死,包括我们的程序的组件也有自己的生命周期,比如web中的servlet,spring的bean也不例外。bean生命周期由多个特定的生命阶段组成,每个生命阶段都留出了一扇门,来供外界对bean施加控制。这节课我们分别对BeanFactory和ApplicationContext中的bean的生命周期来进行解析。
1、BeanFactory中bean什么时候被实例的?
为了研究这个问题,我们要是用一个带有构造方法的People类,并将类配置成bean。
People.java
package com.spring.test;
public class People{
private String name;
private int age;
public People() {
// TODO Auto-generated constructor stub
System.out.println("people类的构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("people类中设置name值");
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
applicationContext.xml
<bean id="people" class="com.spring.test.People">
<property name="name" value="wangdonghui"></property>
<property name="age" value="18"></property>
</bean>
在测试类SpringTest.java中实例出BeanFactory,代码如下:
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resource);
我们发现控制台什么都没有打印,也就证明People没有走构造方法,也就是没有被实例,我们接着在SpringTest.java中写代码:
People people = (People) bf.getBean("people");
发现控制台打印了如下信息
people类的构造方法
people类中设置name值
由此可以证明,对于BeanFactory而言,当其调用getBean方法时,响应的bean才会被实例并赋值。
2、ApplicationContext中bean什么时候被实例的?
结合上个问题的研究思路,我们继续用一个带有构造方法的People类,并将类配置成bean,步骤和上面的问题相同。
接下来我们从SpringTest.java中使用应用上下文获取bean,首先我们将上下文实例出来,代码如下:
ApplicationContext content = new ClassPathXmlApplicationContext("applicationContext.xml");
控制台打印如下:
people类的构造方法
people类中设置name值
由此可以证明,应用上下文实例的时候,bean就已经被创建并且赋值成功了。
3、BeanFactory如何进行bean生命周期的扩展的?
第一个问题研究得出的结论,BeanFactory调用getBean方法后,bean开始实例。我们研究BeanFactory中bean的生命周期也就是从getBean方法调用之后开始。
我们先看一下bean在BeanFactory中生命周期流程图。
猛地一看这个流程图,我们都处于非常懵的状态,不要急,我们一点一点来分解这张图。从这张图中,可以分出三部分的内容
- bean级别的扩展:准确的不能称为扩展了,就是bean类中自己的方法的调用,例如上面提到的构造方法的执行和setter方法的执行。
- bean接口级别的扩展:这个扩展不仅仅是我们创建的bean类了,而是需要我们的bean实现特定的接口,接口中提供了方法,我们可以直接重写接口的方法,然后达到扩展bean生命周期的目的。接口级别的扩展是针对某个类型的bean进行扩展。
- 容器级别的扩展:上面两种扩展都不离开bean,而容器级别的扩展和bean没有关系,他对所有的bean都进行生命周期的扩展,我们称这个容器为“后处理器”
我们接下来就对这三种扩展方式进行详解。
4、哪些流程属于bean级别的扩展呢?
流程图中,蓝色的部分都属于bean级别的扩展,我们可以做出验证,代码如下:
People.java
package com.spring.test;
public class People{
private String name;
private int age;
public People() {
// TODO Auto-generated constructor stub
System.out.println("实例化(构造函数)");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("设置属性值(setter方法)");
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("设置属性值(setter方法)");
this.age = age;
}
public void init() {
System.out.println("init-method属性指定的方法");
}
}
applicationContext.xml
<bean id="people" class="com.spring.test.People" init-method="init">
<property name="name" value="wangdonghui"></property>
<property name="age" value="18"></property>
</bean>
SpringTest.java
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.spring.test.People;
public class SpringTest{
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resource);
People people = (People) bf.getBean("people");
}
}
控制台打印
实例化(构造函数)
设置属性值(setter方法)
设置属性值(setter方法)
init-method属性指定的方法
这样我们就验证了bean级别的三个步骤没有问题。接下来,我们在当前基础上继续研究接口级别的扩展。
5、哪些流程属于bean接口级别的扩展呢?
第3问流程图中红色部分属于属于bean接口级别的扩展,分别有接口BeanNameAware、BeanFactoryAware以及InitializingBean三个接口,我们让People类实现这些接口,并且重写这三个接口的方法。
People.java
package com.spring.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
public class People implements BeanNameAware,BeanFactoryAware,InitializingBean{
private String name;
private int age;
public People() {
// TODO Auto-generated constructor stub
System.out.println("people类的构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("people类的setter方法");
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("people类的setter方法");
this.age = age;
}
public void init() {
System.out.println("people类的init方法");
}
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("InitializingBean的afterPropertiesSet()方法");
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
System.out.println("BeanFactoryAware的setBeanFactory()方法");
}
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println("BeanNameAware的setBeanName()方法");
}
}
applicationContext.xml
<bean id="people" class="com.spring.test.People" init-method="init">
<property name="name" value="wangdonghui"></property>
<property name="age" value="18"></property>
</bean>
SpringTest.java
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.spring.test.People;
public class SpringTest{
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resource);
People people = (People) bf.getBean("people");
}
}
控制台打印
people类的构造方法
people类的setter方法
people类的setter方法
BeanNameAware的setBeanName()方法
BeanFactoryAware的setBeanFactory()方法
InitializingBean的afterPropertiesSet()方法
people类的init方法
这个结果,恰好符合我们第3问中的流程图顺序,下面我们继续对容器级别的扩展进行研究。
6、哪些流程属于容器级别的扩展呢?
图中绿色的都属于容器级别的扩展,可以看出,所有的容器级别扩展都出自类InstantiationAwareBeanPostProcessor和BeanPostProcess。
我们开始提到过了,我们通常称这两个类为“后处理器”。对于这两个处理器接口,我们不能直接让People类直接去实现,不然的话,和bean接口级别扩展还有什么区别呢?当然,你实现了也不会达到我们要的扩展的效果。
我们应该使用一个新的bean去实现后处理器的接口,然后把处理器注册到BeanFactory中,因为两种后处理器,所以有两个实现类。这样,我们就可以使用后处理器实现类扩展BeanFactory中所有的bean了。代码如下:
People.java
package com.spring.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
public class People implements BeanNameAware,BeanFactoryAware,InitializingBean{
private String name;
private int age;
public People() {
// TODO Auto-generated constructor stub
System.out.println("people类的构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("people类的setter方法");
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("people类的setter方法");
this.age = age;
}
public void init() {
System.out.println("people类的init方法");
}
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("InitializingBean的afterPropertiesSet()方法");
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
System.out.println("BeanFactoryAware的setBeanFactory()方法");
}
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println("BeanNameAware的setBeanName()方法");
}
}
MyInstantiationAwareBeanPostProcessor.java
package com.spring.test;
import java.beans.PropertyDescriptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法");
return super.postProcessBeforeInstantiation(beanClass, beanName);
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法");
return super.postProcessAfterInstantiation(bean, beanName);
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法");
return super.postProcessPropertyValues(pvs, pds, bean, beanName);
}
}
MyBeanPostProcess.java
package com.spring.test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcess implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("BeanPostProcessor的postProcessBeforeInitialization()方法");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("BeanPostProcessor的postProcessAfterInitialization()方法");
return bean;
}
}
applicationContext.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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="people" class="com.spring.test.People" init-method="init">
<property name="name" value="wangdonghui"></property>
<property name="age" value="18"></property>
</bean>
<bean id="myInstantiationAwareBeanPostProcessor" class="com.spring.test.MyInstantiationAwareBeanPostProcessor"></bean>
<bean id="myBeanPostProcess" class="com.spring.test.MyBeanPostProcess"></bean>
</beans>
SpringTest.java
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.spring.test.MyBeanPostProcess;
import com.spring.test.MyInstantiationAwareBeanPostProcessor;
import com.spring.test.People;
public class SpringTest{
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resource);
// 两个后处理器实现类的创建
MyInstantiationAwareBeanPostProcessor myInstantiationAwareBeanPostProcessor = (MyInstantiationAwareBeanPostProcessor) bf.getBean("myInstantiationAwareBeanPostProcessor");
MyBeanPostProcess myBeanPostProcess = (MyBeanPostProcess) bf.getBean("myBeanPostProcess");
// BeanFactory注册两个后处理器
((ConfigurableBeanFactory)bf).addBeanPostProcessor(myInstantiationAwareBeanPostProcessor);
((ConfigurableBeanFactory)bf).addBeanPostProcessor(myBeanPostProcess);
People people = (People) bf.getBean("people");
}
}
控制台打印
InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法
people类的构造方法
InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法
InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法
people类的setter方法
people类的setter方法
BeanNameAware的setBeanName()方法
BeanFactoryAware的setBeanFactory()方法
BeanPostProcessor的postProcessBeforeInitialization()方法
InitializingBean的afterPropertiesSet()方法
people类的init方法
BeanPostProcessor的postProcessAfterInitialization()方法
上面代码的打印结果,和我们讨论的流程同一致。
但是值得注意的两个地方,对于MyInstantiationAwareBeanPostProcessor实现类并不是直接实现的InstantiationAwareBeanPostProcessor接口,而是继承了这个接口的适配器InstantiationAwareBeanPostProcessorAdapter。
再一个,就是MyBeanPostProcess后处理器的两个方法返回值必须将参数bean返回过来,不然会有异常抛出,造成bean的丢失。
致此,我们对bean在BeanFactory中的声生命周期探讨完成。
6、bean在ApplicationContext中的生命周期是什么样的呢?
我们在第2问中已经研究过bean在ApplicationContext中被创建的时间,我们对照bean在BeanFactory中的生命周期,看看ApplicationContext中有哪些不同吧!
参考上问的代码,除了SpringTest.java其余的都不改变。我们将SpringTest.java中的代码如下:
SpringTest.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest{
public static void main(String[] args) {
ApplicationContext content = new ClassPathXmlApplicationContext("applicationcontext.xml");
}
}
控制台打印
InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法
people类的构造方法
InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法
InstantiationAwareBeanPostProcessor的postProcessPropertyValues()方法
people类的setter方法
people类的setter方法
BeanNameAware的setBeanName()方法
BeanFactoryAware的setBeanFactory()方法
BeanPostProcessor的postProcessBeforeInitialization()方法
InitializingBean的afterPropertiesSet()方法
people类的init方法
BeanPostProcessor的postProcessAfterInitialization()方法
从上面的打印结果我们可以得出如下结论:
applicationContext实例的时候所有的bean都会创建。
applicationContext会自动注册后处理器,不需要手动注册。
除了上述两点,其余的生命周期和BeanFactory大致相同。(还有不同点,本博客没有体现)