Spring Bean的生命周期小析

Posted 木叶之荣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Bean的生命周期小析相关的知识,希望对你有一定的参考价值。

在上一篇(点击这里观看上一篇)中我们用的BeanPostProcessor、@PostConstruct、InitializingBean等都属于Spring Bean生命周期的内容。在这篇文章中我们简单的说一下Bean的生命周期有关的内容。在Spring中,我们可以从两个层面定义Bean的生命周期:第一个层面是Bean的作用范围(Singleton、Prototype以及Web中的Request、Session和global session),第二个层面是实例化Bean时所经历的一系列阶段。我们将会对BeanFactory和ApplicationContext中的生命周期分别进行分析(BeanFactory和ApplicationContex的一个大的区别是:BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例目标Bean;而ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean。)本篇文章先说BeanFactory的生命周期。

Bean的生命周期所经历的阶段比较多,所以先奉上一个图形化的生命周期的过程。


在上面这个图中我们需要注意这几个类:InstantiationAwareBeanPostProcessor (或InstantiationAwareBeanPostProcessorAdapter)、BeanNameAware、BeanFactoryAware 、BeanPostProcessor 、InitializingBean、DisposableBean。

下面我们详细的来说一下Bean生命周期的过程:

1、当调用者通过getBean(beanName)向容器请求某一个Bean时,如果容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,在实例化Bean之前,将调用接口的postProcessBeforeInstantiation()方法;

2、根据配置情况调用Bean构造函数或工厂方法实例化Bean;

3、如果容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,在实例化Bean之后,调用该接口的postProcessAfterInstantiation()方法,可在这里对已经实例化的对象进行一些操作;

4、如果Bean配置了属性信息,容器在这一步着手将配置值设置到Bean对于的属性中,不过在设置每个属性之前将先调用org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues()方法(如果注册了这个接口的话);

5、调用Bean的属性设置方法设置属性值;

6、如果Bean实现了org.springframework.beans.factory.BeanNameAware接口,将调用setBeanName接口方法,将配置文件中该Bean对应的名称设置到Bean中;

7、如果Bean实现了org.springframework.beans.factory.BeanFactoryAware接口,将调用setBeanFactory()接口方法,将BeanFactory容器实例设置到Bean中;

8、如果BeanFactory装配了org.springframework.beans.factory.config.BeanPostProcessor后处理器,将调用BeanPostProcessor的postProcessBeforeInitialization(Object bean,String beanName)接口方法对Bean进行加工操作,其中入参bean是当前正在处理的Bean,而beanName是当前Bean的配置名,返回的对象为加工处理后的Bean。用户可以使用该方法对某些Bean进行特殊的处理,甚至改变Bean的行为,BeanPostProcessor在Spring框架中占有重要的地位,为容器提供对Bean进行后续加工处理的切入点,Spring容器所提供的各种“神奇功能”(如果AOP、动态代理等)都通过BeanPostProcessor实施;

9、如果Bean实现了org.springframework.beans.factory.InitializingBean接口,将调用afterPropertiesSet()方法;

10、如果在<bean>通过init-method属性定义了初始化方法,将执行这个方法;

11、BeanPostProcessor后处理器定义了两个方法:一个是postProcessBeforeInitialization()方法(在第8步调用);另一个是postProcessAfterInitialization(Object bean,String beanName)方法,这个方法在此时调用,容器再次获得对Bean进行加工处理的机会;

12、如果在<bean>中指定Bean的作用范围为scope=“prototype”,将Bean返回给调用者,调用者负责Bean后续生命周期的管理,Spring不再管理这个Bean的生命周期。如果作用范围设置为scope=“singleton”,则将Bean放入到Spring IoC容器的缓存池中,并将Bean的应用返回给调用者,Spring继续对这些Bean进行后续的生命管理。

13、对于scope=“singleton”的Bean,当容器关闭时,将触发Spring对Bean的后续生命周期的管理工作,首先如果Bean实现了DisposableBean接口,将调用接口的destroy()方法,可以在此编写释放资源、记录日志等操作;

14、对于scope=“singleton”的Bean,如果通过<bean>的destory-method属性指定了Bean的销毁方法,Spring将执行Bean的这个方法,完成Bean资源的释放等操作。

上面一系列的文字看的我们眼花缭乱,我们来总结一下Bean的生命周期。Bean的生命周期大概分为一下三类:

  1. Bean自身的方法:如调用Bean构造函数实例化Bean,调用settter设置Bean的属性值以及通过<bean>的init-method和destory-method所指定的方法;
  2. Bean级生命周期接口方法:像BeanNameAware、BeanFactoryAware、InitalizingBean和DisposableBean,这些接口方法由Bean类直接实现;
  3. 容器级生命周期接口方法:像InstantiationAwareBeanPostProcessor(或InstantiationAwareBeanPostProcessorAdapter)和BeanPostProcessor这两个接口,一般称他们的实现类为后处理器。后处理器接口一般不由Bean自身实现,它们独立于Bean,实现类似容器附加装置的形式注册到Spring容器中并通过接口反射为Spring容器预先识别。当Spring容器创建任何Bean的时候,这些后处理器都会发生作用,所以这些后处理的影响是全局性的。如果有多个容器级的接口的实现的话,可以通过org.springframework.core.annotation.Order注解或者org.springframework.core.Ordered接口来指定执行的顺序。
下面让我们写一个例子来测试一下Bean的生命周期的过程:

Bean的生命周期接口和自身的方法:

package com.zkn.newlearn.spring.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
/**
 * Created by zkn
 * BeanFactoryAware、BeanNameAware、InitializingBean、DisposableBean是Bean级的生命周期接口方法.
 */
public class BeanLifeCycleLearn01 implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean
    /**
     * 姓名
     */
    private String name;
    /**
     * BeanFactory
     */
    private BeanFactory beanFactory;

    private String beanName;

    static 
        System.out.println("BeanLifeCycleLearn01的静态方法块。。。。");
    

    public BeanLifeCycleLearn01() 
        System.out.println("---------调用BeanLifeCycleLearn01的构造器实例化---------");
    

    /**
     * 这是BeanFactoryAware接口方法
     * @see BeanFactoryAware
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException 
        System.out.println("【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()");
        this.beanFactory = beanFactory;
    

    /**
     * 这是BeanNameAware接口方法
     * @see BeanNameAware
     * @param s
     */
    @Override
    public void setBeanName(String s) 
        this.beanName = s;
        System.out.println("【BeanNameAware接口】调用BeanNameAware.setBeanName()");
    

    /**
     * 这是DisposableBean接口方法
     * @see DisposableBean
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception 
        System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()");
    
    /**
     * 这是InitializingBean接口方法
     * @see  InitializingBean
     */
    @Override
    public void afterPropertiesSet() throws Exception 
        System.out.println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()");
    

    public void setName(String name) 
        System.out.println("BeanLifeCycleLearn01调用set方法进行name属性值的设置!");
        this.name = name;
    

    public void initMethod()
        System.out.println("我是配置文件中的init-method。。。。");
    

    public void destoryMethod()
        System.out.println("我是配置文件中的destory-method。。。。");
    

    @Override
    public String toString() 
        return "BeanLifeCycleLearn01" +
            "name='" + name + '\\'' +
            ", beanName='" + beanName + '\\'' +
            '';
    

实现容器级的InstantiationAwareBeanPostProcessor接口:

InstantiationAwareBeanPostProcessor接口是BeanPostProcessor接口的子接口,在Spring1.2中定义的,在Spring2.0中为其提供了一个适配器类org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter,一般情况下,我们可以方便的扩展该适配器覆盖感兴趣的方法以定义实现类。所在我们在这里也是继承的InstantiationAwareBeanPostProcessorAdapter。
package com.zkn.newlearn.spring.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

import java.beans.PropertyDescriptor;

/**
 * Created by zkn
 * InstantiationAwareBeanPostProcessorAdapter:每个Bean在设置属性的时候都会调用者三个方法,在用的时候要慎重.
 */
public class InstantiationAwareBeanPostProcessor01 extends InstantiationAwareBeanPostProcessorAdapter 

    public InstantiationAwareBeanPostProcessor01() 
        super();
        System.out.println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");
    

    /**
     * 接口方法、实例化Bean之前调用
     * @param beanClass
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInstantiation(Class beanClass,
                                                 String beanName) throws BeansException 
        System.out.println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
        return null;
    

    /**
     *  接口方法、实例化Bean之后调用
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException 
        System.out.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
        if(bean instanceof BeanLifeCycleLearn01)
            ((BeanLifeCycleLearn01) bean).setName("我被该名为张四了");
        
        return bean;
    

    /**
     * 接口方法、设置某个属性时调用
     * @param pvs
     * @param pds
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException 
        System.out.println("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");
        return pvs;
    

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException 
        System.out.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInstantiation方法");
        return true;
    

BeanPostProcessor后置处理器:

package com.zkn.newlearn.spring.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
 * Created by zkn
 * BeanPostProcessor:每个Bean都会调用,用的时候要慎重.
 */
public class BeanPostProcessor01 implements BeanPostProcessor 

    public BeanPostProcessor01() 
        System.out.println("这是BeanPostProcessor实现类构造器!!");
    

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException 
        System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!");
        return o;
    

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException 
        System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!");
        return o;
    



Spring的配置文件:

注意:我们这里为BeanLifeCycleLearn01中设置的属性值为zhangsan
<?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">

    <bean id="beanLifeCycleLearn01" class="com.zkn.newlearn.spring.lifecycle.BeanLifeCycleLearn01" init-method="initMethod" destroy-method="destoryMethod">
        <property name="name" value="zhangsan"/>
    </bean>

</beans>

测试方法:

    @Test
    public void testBeanFactoryLifeCycle()
        //1)加载配置文件并启动容器
        DefaultListableBeanFactory df = new DefaultListableBeanFactory();
        new XmlBeanDefinitionReader(df).loadBeanDefinitions(new ClassPathResource("com/zkn/newlearn/spring/lifecycle/beans.xml"));
        //2)向容器中注册BeanPostProcessor后处理器
        df.addBeanPostProcessor(new BeanPostProcessor01());
        //3)向容器中注册InstantiationAwareBeanPostProcessorAdapter后处理器
        df.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor01());
        //4)第一次从容器中获取bean,将触发容器实例化该Bean,这将引发Bean生命周期方法的调用
        BeanLifeCycleLearn01 beanLifeCycle = (BeanLifeCycleLearn01) df.getBean("beanLifeCycleLearn01");
        System.out.println(beanLifeCycle.toString());
        //5)第二次从容器中获取bean,直接从缓存池中获取
        BeanLifeCycleLearn01 beanLifeCycle2 = (BeanLifeCycleLearn01) df.getBean("beanLifeCycleLearn01");
        System.out.println(beanLifeCycle2.toString());
        //6)看看这两次获取的Bean是不是同一个。
        System.out.println("beanLifeCycle == beanLifeCycle2  "+(beanLifeCycle == beanLifeCycle2));
        //7)关闭容器
        df.destroySingletons();
    

输出结果:


从上面的输出结果我们可以看出,输出的结果和我们在上面画的生命周期的图的过程是一样的。如果我们将我们的作用于改为prototype的话,输出结果是这样的:

总结: 通过实现Spring的Bean级生命周期接口对Bean进行一些额外的控制,让Bean具有了更细致的生命周期阶段,但是这也带来了一个问题,它们和代码的耦合度比较高。关于Bean级的生命周期接口中的InitializingBean和DisposableBean,我们通常建议使用<bean>的init-method和destory-method这两个属性为Bean指定初始化和销毁的方法。在Spring2.1中增加了一个InitDestroyAnnotationBeanPostProcessor这个类,我们可以使用@PostConstruct和@PreDestroy注解来指定初始化和销毁的方法。对于容器级的生命周期接口BeanPostProcessor,它不要求Bean去继承它,可以像插件一样注册到Spring容器中,为容器提供额外的功能。

参考:

Spring 3.x 企业应用开发实战   陈雄华 林开雄著。

以上是关于Spring Bean的生命周期小析的主要内容,如果未能解决你的问题,请参考以下文章

Java -- 每日一问:谈谈 Spring Bean 的生命周期和作用域?

Spring中Bean的生命周期

springbean的生命周期是啥?

spring bean的生命周期是怎样的,代码示例

Bean的生命周期

转spring bean的生命周期