說(shuō)說(shuō) Spring Bean 的生命周期

在 Spring 中,我們可以從兩個(gè)層面定義 Bean 的生命周期:

  • Bean 的作用范圍。
  • 實(shí)例化 Bean 時(shí)所經(jīng)歷的一系列階段 。

1 BeanFactory 中 Bean 的生命周期

1.1 生命周期過(guò)程

BeanFactory 中 Bean 的生命周期

過(guò)程如下:

  1. 當(dāng)調(diào)用者通過(guò) getBean(beanName) 向容器請(qǐng)求某一個(gè) Bean 時(shí),如果容器注冊(cè)了 org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,則在實(shí)例化 Bean 之前,將調(diào)用接口的 postProcessBeforeInstantiation() 方法;
  2. 根據(jù)配置情況調(diào)用 Bean 構(gòu)造函數(shù)或工廠方法實(shí)例化 Bean;
  3. 如果容器注冊(cè)了 InstantiationAwareBeanPostProcessor 接口,那么在實(shí)例化 Bean 之后,會(huì)調(diào)用該接口的 postProcessAfterInstantiation() 方法,對(duì)已經(jīng)實(shí)例化的對(duì)象進(jìn)行加工處理;
  4. 如果 Bean 配置了屬性信息,容器將在這一步著手將配置值設(shè)置到 Bean 對(duì)應(yīng)的屬性中,不過(guò)在設(shè)置每個(gè)屬性之前將先調(diào)用 InstantiationAwareBeanPostProcessor 接口的 postProcessPropertyValues() 方法;
  5. 調(diào)用 Bean 的屬性設(shè)置方法設(shè)置屬性值;
  6. 如果 Bean 實(shí)現(xiàn)了 org.springframework.beans.factory.BeanNameAware 接口,將調(diào)用 setBeanName() 接口方法,將配置文件中該 Bean 對(duì)應(yīng)的名稱(chēng)設(shè)置到 Bean 中;
  7. 如果 Bean 實(shí)現(xiàn)了 org.springframework.beans.factory.BeanFactoryAware 接口,則將調(diào)用 setBeanFactory() 接口方法,將 BeanFactory 容器實(shí)例設(shè)置到 Bean 中;
  8. 如果 BeanFactory 裝配了 org.springframework.beans.factory.config.BeanPostProcessor 后處理器,將調(diào)用 BeanPostProcessor 的 Object postProcessBeforeInitialization(Object bean, String beanName) 接口方法對(duì) Bean 進(jìn)行加工操作 。 其中入?yún)?bean 是當(dāng)前正在處理的 Bean ,而 beanName 是當(dāng)前 Bean 的配置名,返回的對(duì)象為加工處理后的 Bean。
  9. 如果 Bean 實(shí)現(xiàn)了 InitializingBean 的接口,將調(diào)用接口的 afterPropertiesSet() 方法;
  10. 如果在 <bean> 通過(guò) init-method 屬性定義了初始化方法,將執(zhí)行這個(gè)方法;
  11. BeanPostProcessor 后處理器定義了兩個(gè)方法:其一是 postProcessBeforeInitialization(),它在第 8 步被調(diào)用;其二是 Object postProcessAfterInitialization(Object bean, String beanName) 方法,這個(gè)方法在此時(shí)被調(diào)用,可以再次對(duì) Bean 進(jìn)行加工處理;
  12. 如果在 <bean> 中指定 Bean 的作用范圍為 scope="prototype",則將 Bean 返回給調(diào)用者,由調(diào)用者負(fù)責(zé) Bean 后續(xù)生命的管理 。 如果作用范圍設(shè)置為 scope="singleton" ,則將 Bean 放入到 Spring IoC 容器的緩存池中,并將 Bean 的引用返回給調(diào)用者, Spring 繼續(xù)對(duì)這些 Bean 進(jìn)行后續(xù)的生命管理;
  13. 對(duì)于 scope="singleton" 的 Bean ,當(dāng)容器關(guān)閉時(shí),將觸發(fā) Spring 對(duì) Bean 的后續(xù)生命周期的管理工作,如果 Bean 實(shí)現(xiàn)了 DisposableBean 接口,則將調(diào)用接口的 afterPropertiesSet()方法,可以在此編寫(xiě)釋放資源 、 記錄日志等操作;
  14. 對(duì)于 scope="singleton" 的 Bean ,如果通過(guò) <bean> 的 destroy-method 屬性指定了 Bean 的銷(xiāo)毀方法, Spring 將執(zhí)行 Bean 的這個(gè)方法,完成 Bean 資源的釋放等操作 。

Bean 的完整生命周期從 Spring 容器著手實(shí)例化 Bean 開(kāi)始,直到最終銷(xiāo)毀 Bean ,這當(dāng)中經(jīng)過(guò)了許多關(guān)鍵點(diǎn),每個(gè)關(guān)鍵點(diǎn)都涉及特定的方法調(diào)用,可以將這些方法大致劃分為 4 類(lèi):

  • Bean 自身的方法:如調(diào)用 Bean 構(gòu)造函數(shù)實(shí)例化 Bean、調(diào)用 Setter 設(shè)置 Bean 的屬性值以及通過(guò) <bean>init-methoddestroy-method 所指定的方法;
  • Bean 級(jí)生命周期接口方法:如 BeanNameAwareBeanFactoryAware、InitializingBeanDisposableBean ,這些接口方法由 Bean 類(lèi)直接實(shí)現(xiàn);
  • 容器級(jí)生命周期接口方法:在上圖中帶 "錨" 的步驟是由InstantiationAwareBeanPostProcessorBeanPostProcessor 這兩個(gè)接口實(shí)現(xiàn)的,一般稱(chēng)它們的實(shí)現(xiàn)類(lèi)為 “后處理器”。 后處理器接口一般不由 Bean 本身實(shí)現(xiàn),它們獨(dú)立于 Bean ,實(shí)現(xiàn)類(lèi)以容器附加裝置的形式注冊(cè)到 Spring 容器中并通過(guò)接口反射被 Spring 容器識(shí)別 。 當(dāng) Spring 容器創(chuàng)建 Bean 時(shí),這些后處理器都會(huì)發(fā)生作用,所以這些后處理器的影響是全局性的 。 當(dāng)然,用戶(hù)也可以通過(guò)合理地編寫(xiě)后處理器,讓其僅對(duì)感興趣 Bean 進(jìn)行加工處理 。
  • 工廠后處理接口方法:包括 AspectJWeavingEanblerCustomAutowireConfigurer、ConfigurationClassPostProcessor 等方法。它們也是容器級(jí)的方法,會(huì)在應(yīng)用上下文裝配好配置文件后,被立即調(diào)用。

Bean 級(jí)生命周期接口和容器級(jí)生命周期接口是個(gè)性和共性辯證統(tǒng)一思想的體現(xiàn),前者解決了 Bean 個(gè)性化處理的問(wèn)題;而后者解決了容器中某些 Bean 共性化處理的問(wèn)題 。

Spring 容器中可以注冊(cè)多個(gè)后處理器 。 只要它們同時(shí)實(shí)現(xiàn)了 org.springframework.core.Ordered 接口,容器將按特定的順序依次調(diào)用這些后處理器 。 在上圖中帶 “錨” 的步驟,都可以調(diào)用多個(gè)后處理器進(jìn)行一系列的加工處理操作 。

InstantiationAwareBeanPostProcessorBeanPostProcessor 接口的子接口,它的適配器類(lèi)是 InstantiationAwareBeanPostProcessorAdapter ,我們可以方便地?cái)U(kuò)展這個(gè)適配器類(lèi)來(lái)自定義自己感興趣的方法。

1.2 體驗(yàn)生命周期

我們創(chuàng)建一個(gè)類(lèi),讓它實(shí)現(xiàn)所有 Bean 級(jí)的生命周期接口,此外,還通過(guò) <bean> 的 init-method 和 destroy-method 屬性定義了 Bean 初始化和 Bean 銷(xiāo)毀的方法。

public class People implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean{

    /**
     * 姓名
     */
    private String name;

    /**
     * 年齡
     */
    private int age;

    /**
     * 默認(rèn)構(gòu)造函數(shù)
     */
    public People() {
    }

    /**
     * 帶參數(shù)的構(gòu)造函數(shù)
     *
     * @param name
     * @param age
     */
    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

  

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("setBeanName");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }

    public void customInit(){
        System.out.println("自定義 customInit");
    }

    public void customDestroy(){
        System.out.println("自定義 customDestroy");
    }
}

XML 配置:

<bean id="people" class="net.deniro.springBoot.spring4.IoC.People"
  init-method="customInit"
  destroy-method="customDestroy"
    />

通過(guò)繼承 InstantiationAwareBeanPostProcessorAdapter,可以自定義后處理器:

public class CustomInstantiationAwareBeanPostProcessor extends
        InstantiationAwareBeanPostProcessorAdapter {

    public static final String PEOPLE_BEAN = "people";

    /**
     * 在實(shí)例化 Bean 之前調(diào)用
     *
     * @param beanClass
     * @param beanName
     * @return
     * @throws BeansException
     */
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (PEOPLE_BEAN.equals(beanName)) {
            System.out.println("postProcessBeforeInstantiation");
        }
        return null;
    }

    /**
     * 在實(shí)例化 Bean 之后調(diào)用
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (PEOPLE_BEAN.equals(beanName)) {
            System.out.println("postProcessAfterInstantiation");
        }
        return true;
    }

    /**
     * 設(shè)置某個(gè)屬性
     *
     * @param pvs
     * @param pds
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        if (PEOPLE_BEAN.equals(beanName)) {
            System.out.println("postProcessPropertyValues");
        }
        return pvs;
    }

}

還可以通過(guò)實(shí)現(xiàn) CustomBeanPostProcessor,來(lái)自定義后處理器,我們可以針對(duì)那些感興趣的 Bean 進(jìn)行加工處理:

public class CustomBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals(PEOPLE_BEAN)) {
            People people = (People) bean;
            if (people.getName() == null) {
                people.setName("deniro");
                System.out.println("postProcessBeforeInitialization:"+people);
            }
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals(PEOPLE_BEAN)) {
            People people = (People) bean;
            if (people.getAge() == 0) {
                people.setAge(25);
                System.out.println("postProcessAfterInitialization:"+people);
            }
        }
        return bean;
    }
}

測(cè)試代碼:

/**
 * 加載配置文件并啟動(dòng)
 */
Resource resource = new ClassPathResource("beans2.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(
        factory);
reader.loadBeanDefinitions(resource);

//注冊(cè)后處理器
factory.addBeanPostProcessor(new CustomBeanPostProcessor());
factory.addBeanPostProcessor(new CustomInstantiationAwareBeanPostProcessor());

//從容器中獲取 People,實(shí)例化該 Bean,這將引發(fā) Bean 生命周期方法的調(diào)用
People people1 = (People) factory.getBean("people");
System.out.println("people1:" + people1);
people1.setName("lily");
System.out.println("new people1:" + people1);

//第二次從緩存池中獲取 Bean
People people2 = (People) factory.getBean("people");
System.out.println("people1==people2:" + (people1 == people2));

//關(guān)閉容器
factory.destroySingletons();

我們首先裝載了配置文件并啟動(dòng)容器 。 然后向容器中注冊(cè)了 CustomBeanPostProcessor 處理器。 如果有多個(gè)后處理器,可按照相似的方式調(diào)用 addBeanPostProcessor() 方法進(jìn)行注冊(cè),需要強(qiáng)調(diào)的是,后處理器的實(shí)際調(diào)用順序和注冊(cè)順序是無(wú)關(guān)的,在具有多個(gè)后處理器的情況下,必須通過(guò)實(shí)現(xiàn)的 org.springframework.core.Ordered 接口以確定調(diào)用順序 。

1.3 討論

可以通過(guò) <bean> 的 init-method 和 destroy-method 屬性的配置方式為 Bean 指定初始化和銷(xiāo)毀的方法,這樣可以實(shí)現(xiàn)業(yè)務(wù)類(lèi)完全 POJO 化,這些類(lèi)只實(shí)現(xiàn)自己的業(yè)務(wù)接口,不需要和某個(gè)特定框架(包括 Spring 框架)的接口關(guān)聯(lián),從而達(dá)到了與框架解耦的目的。

Spring 中還添加了一個(gè) InitDestroyAnnotationBeanPostProcessor ,該 Bean 后處理器將對(duì)標(biāo)注了 @PostConstruct、@PreDestroy 注解的 Bean 進(jìn)行處理,在 Bean 初始化后及銷(xiāo)毀前執(zhí)行相應(yīng)的邏輯 。 如果在 ApplicationContext 中,則默認(rèn)裝配了該處理器。

BeanFactoryAware 接口可以讓 Bean 感知容器(即 BeanFactory 實(shí)例),而 BeanNameAware 接口可以讓 Bean 獲得配置文件中對(duì)應(yīng)的配置名稱(chēng) 。 如果希望 Bean 獲取容器中的其他 Bean ,則可以通過(guò)屬性注入的方式引用這些 Bean ,如果 Bean 希望在運(yùn)行期獲知在配置文件中的 Bean 名稱(chēng),也可以簡(jiǎn)單地將名稱(chēng)作為屬性注入 。

所以除非想要編寫(xiě)一個(gè)基于 Spring 之上的擴(kuò)展插件或子項(xiàng)目,否則用戶(hù)完全可以?huà)侀_(kāi)Bean 生命周期的接口類(lèi) 。

而 BeanPostProcessor 接口要求 Bean 去繼承它,所以可以完全像一個(gè)插件那樣,把它注冊(cè)到 Spring 容器中,從而為容器提供額外功能 。比如 Spring 容器就利用了 BeanPostProcessor 對(duì) Bean 進(jìn)行加工處理,比如 Spring 的 AOP 功能。

2 ApplicationContext 中 Bean 的生命周期

Bean 在應(yīng)用上下文中的生命周期和在 BeanFactory 中的生命周期類(lèi)似,不同是,如果 Bean 實(shí)現(xiàn)了 org.springframework.context.ApplicationContextAware 接口,則會(huì)增加一個(gè)調(diào)用該接口方法 setApplicationContext() 的步驟。

如果配置文件中定義了多個(gè)工廠后處理器,需要讓它們實(shí)現(xiàn) org.springframework.core.Ordered 接口,這樣才能讓 Spring 以確定的順序調(diào)用它們 。 工廠后處理器是容器級(jí)的,僅在應(yīng)用上下文初始化時(shí)調(diào)用一次,用于完成一些配置文件的加工處理工作 。

ApplicationContextBeanFactory 另一個(gè)不同之處是:前者會(huì)利用 Java 的反射機(jī)制自動(dòng)識(shí)別出配置文件中定義的 BeanPostProcessor、InstantiationAwareBeanPostProcessorBeanFactoryPostProcessor,并自動(dòng)將它們注冊(cè)到應(yīng)用上下文中;而后者需要在代碼中通過(guò)手工調(diào)用 addBeanPostProcessor() 方法進(jìn)行注冊(cè) 。 這也是為什么在應(yīng)用開(kāi)發(fā)時(shí),我們普遍使用的是 ApplicationContext 而很少使用 BeanFactory 的原因之一 。

ApplicationContext 中,我們只需要在配置文件中通過(guò) <bean> 定義工廠后處理器和 Bean 后處理器,它們就會(huì)按照預(yù)期的方式運(yùn)行 。

ApplicationContext 中 Bean 的生命周期

現(xiàn)在請(qǐng)看一個(gè)使用工廠后處理器的實(shí)例,我們?cè)诖烁淖兞? people 實(shí)例的 name:

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition definition=beanFactory.getBeanDefinition("people");

        definition.getPropertyValues().addPropertyValue("name","jack");
        System.out.println("CustomBeanFactoryPostProcessor.postProcessBeanFactory()");
    }
}

ApplicationContext 在啟動(dòng)時(shí),將首先為配置文件中每個(gè) <bean> 生成一個(gè) BeanDefinition 對(duì)象, BeanDefinition 是 <bean> 在 Spring 容器中的內(nèi)部表示 。

配置文件:

<bean id="people" class="net.deniro.spring4.IoC.People"
     init-method="customInit"
     destroy-method="customDestroy"
       />

<!-- 工廠的后處理器-->
<bean id="customBeanFactoryPostProcessor"
     class="net.deniro.spring4.bean.CustomBeanFactoryPostProcessor"/>

<!-- 注冊(cè) Bean 的后處理器-->
<bean id="customBeanPostProcessor"
     class="net.deniro.spring4.bean.CustomBeanPostProcessor"/>

定義的 BeanPostProcessor 和 BeanFactoryPostProcessor 會(huì)自動(dòng)被 ApplicationContext 識(shí)別并注冊(cè)到容器中 。 啟動(dòng)容器(比如 tomcat)就可以看到結(jié)果啦O(∩_∩)O哈哈~

注意:需要在 web.xml 中設(shè)置 spring 配置文件:

...
<!-- 加載 Spring 配置文件-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:beans2.xml</param-value>
</context-param>
...
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,502評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,253評(píng)論 6 342
  • 本來(lái)是準(zhǔn)備看一看Spring源碼的。然后在知乎上看到來(lái)一個(gè)帖子,說(shuō)有一群**自己連Spring官方文檔都沒(méi)有完全讀...
    此魚(yú)不得水閱讀 7,036評(píng)論 4 21
  • 什么是Spring Spring是一個(gè)開(kāi)源的Java EE開(kāi)發(fā)框架。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,764評(píng)論 1 133
  • 假期第一天,提前做好了計(jì)劃,帶孩子們和媽媽一起去平原新區(qū)。三個(gè)孩子在一起的一天,小摩擦和哭鬧聲不斷。特別是淑馨和...
    美樂(lè)晴閱讀 329評(píng)論 0 0

友情鏈接更多精彩內(nèi)容