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的擴展類。

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