菜鸟的成长之路——bean的生命周期

  所有的事物,都会有自己的生老病死,包括我们的程序的组件也有自己的生命周期,比如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大致相同。(还有不同点,本博客没有体现)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值