spring容器Bean的生命周期及BeanPostProcessor的使用

生命周期流程

在这里插入图片描述

  1. 1~2创建实例。创建实例就是:这里就是把配置文件中的bean信息化作一个bean读取到容器里面
  2. 3~4是注入依赖关系,3是对bean实例化之后做一些操作,4是配置文件中的bean属性设置到bean中
  3. 5是bean初始化之前的处理,应用开发者需要把容器中实例化的bean拿出来用,这个拿出来的过程就是初始化注意实例化与初始化的区别,instantiation 和initialization
  4. 6~7 如果bean实现了InitializingBean,那么将调用InitializingBean的afterPropertiesSet()方法做一些初始化处理。如果没有实现InitializingBean,而是在配置文件中定义了init-method属性值,那么系统会找到init-method对应的方法并执行之,一般在这个方法里写一些初始化操作
  5. 8是初始化之后的操作,可以在初始化后进行一些修饰
  6. 9~10是交给应用开发者使用,如果在中指定Bean的作用范围是scopt=“prototype”,那么系统将bean返回给调用者,spring就不管了(如果两个实例调用的话,每一次调用都要重新初始化,一个实例的修改不会影响另一个实例的值。如果指定Bean的作用范围是scope=“singleton”,则把bean放到缓冲池中,并将bean的引用返回给调用者。这个时候,如果两个实例调用的话,因为它们用的是同一个引用,任何一方的修改都会影响到另一方。)
  7. 11是bean用完之后,对于scope="singleton"的bean,使用完之后spring容器会做一些处理,比如编写释放资源、记录日志等操作。
  8. 12是配置文件中自己配置的销毁方法

举个栗子🌰

applicationContext.xml是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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.xsd
                    http://www.springframework.org/schema/aop
                    http://www.springframework.org/schema/aop/spring-aop.xsd
                    http://www.springframework.org/schema/tx
                    http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="eason" class="person.shw.spring.sourcecode.pojo.Eason" init-method="myInit" destroy-method="myDestory" scope="singleton">
        <property name="girlFriend" value="还没有女朋友"/>
        <property name="profession" value="歌手"/>
        <property name="sex" value=""/>
    </bean>

</beans>

MyInstantiationAwareBeanPostProcessor.java配置增强类

 package person.shw.spring.sourcecode.inistantiation;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import person.shw.spring.sourcecode.pojo.Eason;

import java.beans.PropertyDescriptor;

/**
 * @author shihaowei
 * @date 2020-06-15 18:12
 */
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {


    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("eason")){
            System.err.println("MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation");
        }

        return null;
    }

    /**
     * 实例化bean后的增强修饰
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("eason")){
            System.err.println("MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation");
        }
        return true;
    }

    /**
     * 把配置文件值复制给属性
     * @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 {
        if (beanName.equals("eason")){
            Eason eason = (Eason)bean;
            System.err.println("MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues");

        }

        return pvs;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

上面的类是继承了InstantiationAwareBeanPostProcessorAdopter的,而InstantiationAwareBeanPostProcessorAdopter这个适配器与是InstantiationAwareBeanPostProcessor的扩展类。

public class MyBeanPostProcessor implements BeanPostProcessor {

    Log log = LogFactory.getLog(MyBeanPostProcessor.class);

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("eason")) {
            Eason eason = (Eason) bean;
            log.info("配置文件中eason的女朋友是:"+eason.getGirlFriend());
            eason.setGirlFriend("杨千嬅");
            log.info("调用BeanPostProcessor的postProcessBeforeInitialization处理后," +
                    "eason的女朋友变为:"+eason.getGirlFriend());
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("eason")) {
            Eason eason = (Eason)bean;
            log.info("eason当前的女朋友是:"+eason.getGirlFriend());
            eason.setGirlFriend("徐濠萦");
            log.info("调用BeanPostProcessor的postProcessAfterInitialization处理后," +
                    "eason的女朋友变成:"+eason.getGirlFriend());
        }

        return bean;
    }
}

上面的代码实现了BeanPostProcessor。InstantiationAwareBeanPostProcessor是实例化前后做的事情,BeanPostProcessor是初始化前后做的事情,它们之间应该存在着父子关系吧?当然是,从名字就能看出来前者是后者的扩展类,读者可以自己下载spring源码查看。这两个类定义好了需要注册才能使用(把它们注册到spring容器中使用),稍后再讲。这里先讲bean类:

/**
 * @author shihaowei
 * @date 2020-06-15 16:57
 */
public class Eason implements InitializingBean, DisposableBean {

    Log log = LogFactory.getLog(Eason.class);

    private String sex;
    private String profession;
    private String girlFriend;


    public Eason() {
        log.info("调用Eason默认无参构造函数,Eason出道了");
    }


    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getProfession() {
        return profession;
    }

    public void setProfession(String profession) {
        this.profession = profession;
    }

    public String getGirlFriend() {
        return girlFriend;
    }

    public void setGirlFriend(String girlFriend) {
        this.girlFriend = girlFriend;
    }

    public void myInit(){
        this.girlFriend = "eason正在追徐濠萦";
        log.info("通过调用配置文件初始化女朋友为:"+this.girlFriend);
    }

    public void myDestory(){
        log.info("调用myDestory()");
    }

    public void destroy() throws Exception {
        log.info("调用DisposableBean.destory(),销毁");
    }

    public void afterPropertiesSet() throws Exception {
        this.profession = "歌手";
        log.info("调用InitializingBean.afterPropertiesSet()," +
                "属性配置完毕了再做些善后工作。");
    }

    @Override
    public String toString() {
        return "Eason{" +
                "sex='" + sex + '\'' +
                ", profession='" + profession + '\'' +
                ", girlFriend='" + girlFriend + '\'' +
                '}';
    }
}

这个bean实现了InitializingBean,DisposableBean,那么第六步和第11步就可以用得到了,下面是注册和测试方法:

public class BeanLifeCycleMain {

    private static Log log= LogFactory.getLog(BeanLifeCycleMain.class);

    private static void lifeCycleInBeanFactory(){
        Resource resource = new ClassPathResource("applicationContext.xml");
        启动一个xml的容器
        XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
		// 这里是注册事件
        ((ConfigurableBeanFactory)beanFactory).addBeanPostProcessor(new MyBeanPostProcessor());
        ((ConfigurableBeanFactory)beanFactory).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());

        Eason eason = (Eason) beanFactory.getBean("eason");
        log.info("eason:"+eason.toString());
        //((XmlBeanFactory)beanFactory).destroySingletons();
        Eason eason2 = (Eason) beanFactory.getBean("eason");
        eason2.setGirlFriend("杨千嬅");
        log.info("eason2:"+eason2.toString());
        log.info("eason:"+eason.toString());
        log.info(eason == eason2);
    }

    public static void main(String[] args) {
        lifeCycleInBeanFactory();
    }
}

下面我们看一下日志结果

MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason <init>
信息: 调用Eason默认无参构造函数,Eason出道了
MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 配置文件中eason的女朋友是:还没有女朋友
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 调用BeanPostProcessor的postProcessBeforeInitialization处理后,eason的女朋友变为:杨千嬅
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason afterPropertiesSet
信息: 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason myInit
信息: 通过调用配置文件初始化女朋友为:eason正在追徐濠萦
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: eason当前的女朋友是:eason正在追徐濠萦
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: 调用BeanPostProcessor的postProcessAfterInitialization处理后,eason的女朋友变成:徐濠萦
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='徐濠萦'}
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason2:Eason{sex='男', profession='歌手', girlFriend='杨千嬅'}
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='杨千嬅'}
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: true
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason destroy
信息: 调用DisposableBean.destory(),销毁
六月 16, 2020 11:37:01 上午 person.shw.spring.sourcecode.pojo.Eason myDestory
信息: 调用myDestory()

行1:实例化之前处理了一些事情。
行2~3:duang!开始实例化,实例化当然首先要执行构造函数(这是美好世界的窗口)。
行4:实例化之后处理了一些事情。
行5:实例化之后注入属性值之前要调用这个函数。
行6~7:注入xml的属性值,可以看到是配置中的"还没有女朋友"。
行8~9:注入属性值后,随即又把女朋友这个属性的值改为了"杨千嬅"。
行10~11:属性配置完毕了做一些善后工作。在Eason类我把职业改为了"歌手",所以后面显示的职业都是"歌手",而不是配置文件中的"歌手,演员,导演,主持"。
行12~13:调用了配置文件中的init-method。通过的class属性找到这个类,再找到属性值对应的这个方法执行。但是实现必须implements InitializingBean,给代码带来复杂度和污染。
行14和行17是初始化之后做的事情,首先显示当前女朋友,又把女朋友改为了徐濠萦。
行18-行25:看对应的代码就会发现,两个对象其实引用的是同一个地址,eason2修改了属性之后eason1也会跟着作改变,这就是singleton配置方式的作用。
行26是关闭容器。
行28,一个是调用DisposableBean的销毁,一个是调用配置文件的销毁

那么如果把配置文件的scope属性改为"prototype"会发生什么呢?让我们看一下打印的日志:

MyInstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason <init>
信息: 调用Eason默认无参构造函数,Eason出道了
MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 配置文件中eason的女朋友是:还没有女朋友
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 调用BeanPostProcessor的postProcessBeforeInitialization处理后,eason的女朋友变为:杨千嬅
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason afterPropertiesSet
信息: 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason myInit
信息: 通过调用配置文件初始化女朋友为:eason正在追徐濠萦
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: eason当前的女朋友是:eason正在追徐濠萦
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: 调用BeanPostProcessor的postProcessAfterInitialization处理后,eason的女朋友变成:徐濠萦
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='徐濠萦'}
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason <init>
信息: 调用Eason默认无参构造函数,Eason出道了
MyInstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
MyInstantiationAwareBeanPostProcessor.postProcessPropertyValues
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 配置文件中eason的女朋友是:还没有女朋友
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessBeforeInitialization
信息: 调用BeanPostProcessor的postProcessBeforeInitialization处理后,eason的女朋友变为:杨千嬅
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason afterPropertiesSet
信息: 调用InitializingBean.afterPropertiesSet(),属性配置完毕了再做些善后工作。
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.pojo.Eason myInit
信息: 通过调用配置文件初始化女朋友为:eason正在追徐濠萦
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: eason当前的女朋友是:eason正在追徐濠萦
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.processor.MyBeanPostProcessor postProcessAfterInitialization
信息: 调用BeanPostProcessor的postProcessAfterInitialization处理后,eason的女朋友变成:徐濠萦
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason2:Eason{sex='男', profession='歌手', girlFriend='杨千嬅'}
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: eason:Eason{sex='男', profession='歌手', girlFriend='徐濠萦'}
六月 16, 2020 11:39:22 上午 person.shw.spring.sourcecode.bean.BeanLifeCycleMain lifeCycleInBeanFactory
信息: false

当创建eason2对象时,又进行了一次初始化的过程,日志对比两个对象为false,说明两个对象不同了,这就是prototype的作用。
 ApplicationContext中Bean的生命周期与BeanFactory类似,但是又有不同。对于InstantiationAwareBeanPostProcessor和MyBeanPostProcessor,BeanFactory需要在代码中注册方才能使用,而ApplicationContext只需要在xml中配置,spring会自动将它们注册到应用上下文中,这是二者最大的区别,也是为什么普遍使用ApplicationContext而非BeanFactory的原因。ApplicationContext是BeanFactory的扩展类。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章