1. 程式人生 > >spring原始碼閱讀筆記10:bean生命週期

spring原始碼閱讀筆記10:bean生命週期

  前面的文章主要集中在分析Spring IOC容器部分的原理,這部分的核心邏輯是和bean建立及管理相關,對於單例bean的管理,從建立好到快取起來再到銷燬,其是有一個完整的生命週期,並且Spring也在整個bean的建立過程中提供了多處介面供使用者自己擴充套件,本文就來梳理一下Spring中的bean生命週期。

1. Spring 容器中 Bean 的生命週期

  對於prototype作用域的Bean,Spring容器僅僅負責建立,當容器建立了Bean例項之後,Bean例項完全交給客戶端程式碼管理,容器不再跟蹤其生命週期。每次客戶端請求prototype作用域的Bean時,Spring都會產生一個新的例項,Spring容器無法知道它曾經創造了多少個prototype作用域的Bean,也無從知道這些prototype作用域的Bean什麼時候才會銷燬。因此,Spring無法管理prototype作用域的Bean。

  對於singleton作用域的Bean,每次客戶端程式碼請求時,都返回同一個共享例項,客戶端程式碼不能控制Bean的銷燬,Spring容器負責跟蹤Bean例項的產生、銷燬。Spring容器可以在建立Bean之後,進行某些通用資源的申請;還可以在銷燬Bean例項之前,先回收某些資源,比如資料庫連線等。

  先來看一下Spring Bean的完整生命週期,從建立Spring容器開始,直到最終Spring容器銷燬Bean:

  我們將Spring容器中Bean的生命週期級別分為四級,分別是:

  • Bean自身方法;
  • Bean級生命週期介面方法;
  • 容器級生命週期介面方法;
  • 工廠後處理器介面方法。

1.1 Bean自身方法

  Bean自身的方法:呼叫建構函式例項化bean,呼叫setter設定屬性,呼叫init-method,destroy-method。

1.2 Bean級生命週期介面方法

  Bean級生命週期方法:如BeanNameAware,BeanFactoryAware,InitializingBean和DisposableBean,這些介面由bean直接實現。

1.3 容器級生命週期介面方法

  容器級生命週期介面方法:有InstantiationAwareBeanPostProcessor和BeanPostProcessor這兩個介面實現,一般稱他們的實現類為後處理器。實現類獨立於bean,以容器附加裝置的形式註冊到spring當中。當spring建立任何bean時,這些後處理器都會發生作用,所以後處理器的影響是全域性性的。當然,使用者可以通過合理的編寫後處理器,讓其僅對感興趣的bean進行加工處理。

  Bean級生命介面和容器級生命介面是個性和共性辯證統一思想的體現。前者解決bean的個性化處理的問題,後者解決容器中某些bean共性化處理的問題。

1.4 工廠後處理器介面方法

  工廠級生命週期介面方法(BeanFactoryPostProcessor介面的實現類),可以對bean的定義(配置元資料)進行處理。也就是說,Spring IoC容器允許BeanFactoryPostProcessor在容器實際例項化任何其它的bean之前讀取配置元資料,並有可能修改它。

2. bean生命週期演示示例

  下面通過一個例子來實際體驗一下bean的生命週期中的各個關鍵介面方法的呼叫。FruitStore類中定義了Bean自身方法以及Bean級生命週期方法:

public class FruitStore implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean{

    private String name;  
    private String address;  
    
    private ApplicationContext applicationContext;  
    private String             beanName;  
  
    public FruitStore() {  
        System.out.println("[FruitStore]--構造器");  
    }
    
    /** Bean自身方法 **/  
    
    // 通過<bean>的init-method屬性指定的初始化方法  
    public void myInit() {  
        System.out.println("[Bean自身方法] [init-method]  初始化方法...");  
    }  
      
    // 通過<bean>的destroy-method屬性指定的初始化方法  
    public void myDestory() {  
        System.out.println("[Bean自身方法] [destroy-method]  銷燬方法...");  
    }  
      
    public void sayHello() {  
        System.out.println("[Bean自身方法]  sayHello...");  
    }
    
    /** Bean級生命介面方法begin **/  
    
    public void setName(String name) {  
        this.name = name;  
        System.out.println("[Bean級介面] [注入屬性]  注入屬性name...");  
    }  
  
    public void setAddress(String address) {  
        this.address = address;  
        System.out.println("[Bean級介面] [注入屬性]  注入屬性address...");  
    }
    
    
    // DiposibleBean介面方法
    public void destroy() throws Exception {
        System.out.println("[Bean級介面]  銷燬方法...");
    }

    // InitializingBean介面方法
    public void afterPropertiesSet() throws Exception {
        System.out.println("[Bean級介面] [InitializingBean介面]  初始化方法...");
    }

    // BeanFactoryAware介面方法
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        this.applicationContext = arg0;  
        System.out.println("[Bean級介面] [ApplicationContextAware介面]  注入Spring容器ApplicationContext..."); 
    }

    // BeanNameAware介面方法
    public void setBeanName(String name) {
        this.beanName = name;  
        System.out.println("[Bean級介面] [BeanNameAware介面]  注入beanName...");
    }
    
    @Override  
    public String toString() {  
        return "FruitStore [name=" + name + 
                ", address=" + address + 
                ", applicationContext=" + applicationContext + 
                ", beanName=" + beanName + 
                "]";  
    } 
}

  分別實現兩種容器級介面,首先是InstantiationAwareBeanPostProcessor介面:

public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    
    public MyInstantiationAwareBeanPostProcessor() {  
        super();  
        System.out.println("[容器級介面] [InstantiationAwareBeanPostProcessor實現類]--構造器");  
    }  
  
    // 例項化Bean之前呼叫  
    @Override  
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {  
        System.out.println("[容器級介面] [InstantiationAwareBeanPostProcessor實現類]--例項化Bean之前呼叫");  
        return null;  
    }  
  
    // 例項化Bean之後呼叫  
    @Override  
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {  
        System.out.println("[容器級介面] [InstantiationAwareBeanPostProcessor實現類]--例項化Bean之後呼叫");  
        return true;  
    }  
  
    // 初始化Bean之前呼叫  
    @Override  
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
        System.out.println("[容器級介面] [InstantiationAwareBeanPostProcessor實現類]--初始化Bean之前呼叫");  
        return bean;  
    }  
  
    // 初始化Bean之後呼叫  
    @Override  
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
        System.out.println("[容器級介面] [InstantiationAwareBeanPostProcessor實現類]--初始化Bean之後呼叫");  
        return bean;  
    }  
  
    // 設定某個屬性時呼叫  
    @Override  
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,  
            String beanName) throws BeansException {  
        System.out.println("[容器級介面] [InstantiationAwareBeanPostProcessor實現類]--例項化Bean之後,設定某個屬性時呼叫");  
        return pvs;  
    }  
}

  然後實現BeanPostProcessor介面:

public class MyBeanPostProcessor implements BeanPostProcessor{

    public MyBeanPostProcessor() {  
        System.out.println("[容器級介面] [MyBeanPostProcessor實現類]--構造器");  
    }  
  
    // 初始化Bean之前呼叫  
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
        System.out.println("[容器級介面] [BeanPostProcessor實現類]--初始化Bean之前呼叫");  
        return bean;  
    }  
  
    // 初始化Bean之後呼叫  
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
        System.out.println("[容器級介面] [BeanPostProcessor實現類]--初始化Bean之後呼叫");  
        return bean;  
    }  
}

  工廠級生命週期介面方法(BeanFactoryPostProcessor介面的實現類):

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{

    public MyBeanFactoryPostProcessor() {  
        super();  
        System.out.println("[工廠級介面] [BeanFactoryPostProcessor實現類]--構造器");  
    }  
    
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {  
        System.out.println("[工廠級介面] [BeanFactoryPostProcessor實現類] Spring容器載入之後,所有Bean例項化之前呼叫");  
        // 重寫Person Bean的phone屬性  
        BeanDefinition bd = arg0.getBeanDefinition("fruitStore");  
        bd.getPropertyValues().addPropertyValue("name", "papaya-mangos");  
    }  
}

  配置檔案:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    
        <!-- 定義工廠級生命週期介面. -->  
    <bean id="beanFactoryPostProcessor" class="spring.source.MyBeanFactoryPostProcessor"></bean>  
  
    <!-- 定義容器級生命週期介面. -->  
    <bean id="beanPostProcessor" class="xxx.xxx"></bean>  
    <bean id="instantiationAwareBeanPostProcessor" class="xxx.xxx"></bean>  
      
    <!-- 定義Bean自身及Bean級生命週期介面. -->  
    <bean id="fruitStore" class="xxx.xxx"   
            init-method="myInit"   
            destroy-method="myDestory"   
            scope="singleton">  
        <property name="name"    value="永輝超市"></property>  
        <property name="address" value="杭州"></property>   
    </bean>  
</beans>

  測試程式碼:

public static void main(String[] args) {
        try{
            System.out.println("============================== 現在開始初始化容器. ==============================");
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");    
       System.out.println("\r\n============================== 容器初始化成功. =============================="); //得到Preson,並使用 FruitStore fruitStore = ctx.getBean("fruitStore",FruitStore.class); fruitStore.sayHello(); System.out.println(fruitStore); System.out.println("\r\n============================== 現在開始關閉容器! =============================="); ctx.close(); }catch (Exception e){ e.printStackTrace(); } }

  執行結果為:

  這裡再分析上述執行結果:

  1. 準備Spring容器

    • 例項化BeanFactoryPostProcessor實現類;
    • 執行BeanFactoryPostProcessor的postProcessBeanFactory修改XML對Bean配置的元資訊,這裡是改了一下fruitStore這個Bean的name屬性值;
  2. 例項化Bean

    • 例項化BeanPostProcessor實現類;
    • 例項化InstantiationAwareBeanPostProcessorAdapter實現類;
    • Bean例項化之前呼叫InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法;
    • 呼叫FruitStore的構造器進行例項化;
    • Bean例項化之後呼叫InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法;
    • 在屬性注入之前,呼叫InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法,可以修改Bean的屬性資訊;
  3. 注入依賴關係

    • 注入屬性:name、address;
  4. 初始化Bean

    • 注入BeanName;
    • 注入ApplicationContext;
    • 初始化Bean之前呼叫BeanPostProcessor實現類呼叫介面方法postProcessBeforeInitialization;
    • 初始化Bean之前呼叫InstantiationAwareBeanPostProcessor的postProcessBeforeInitialization方法;
    • 呼叫InitializingBean實現類的afterPropertiesSet()進行Bean的初始化;
    • 呼叫<bean>的init-method屬性指定的初始化方法;
    • 初始化Bean之後呼叫BeanPostProcessor實現類介面方法postProcessAfterInitialization;
    • 初始化Bean之後呼叫InstantiationAwareBeanPostProcessor的postProcessAfterInitialization方法;
  5. 使用Bean

    • 呼叫sayHello()方法;
    • 列印FruitStore資訊(可以發現名稱name已改為papaya-mangos,和配置檔案中不同);
  6. 銷燬Bean

    • 呼叫DiposibleBean介面的destory方法;
    • 呼叫<bean>的destroy-method屬性指定的銷燬方法;

3. 總結

  本文我們總結了Spring中Bean的生命週期,主要有如下流程:

  • Spring容器準備,這裡可以應用工廠級別的後處理器BeanFactoryPostProcessor的實現類;
  • 例項化Bean,這裡可以應用容器級別的後處理InstantiationAwareBeanPostProcessor的實現類來在例項化Bean前後做一些處理;
  • 依賴注入,這裡可以應用容器級別後處理器InstantiationAwareBeanPostProcessor的實現類來在屬性注入之前做一些處理;
  • 對Bean進行初始化,這裡可以應用Bean級生命週期介面方法(BeanNameAware、InitializingBean等介面)及容器級後處理器BeanPostProcessor實現類;
  • 使用Bean;
  • 銷燬Bean,這裡會應用Bean級生命週期介面方法DisposableBean及Bean自身方法destroy-method;

  總結了常見的配置Bean生命週期的方式主要有三種:

  • 繼承介面,如BeanNameAware、InitializingBean等;
  • 配置xml配置檔案,如init-method,destroy-method;
  • 新增處理器,如實現BeanPostProcessor;

  通過<bean>的init-method和destroy-method屬性配置方式為bean指定初始化和銷燬的方法,採用這種方式的效果和通過實現InitializingBean,DisposableBean介面所達到的效果是完全相同的,但是採用前者配置方式可以使bean不需要和特定的spring介面繫結,前者是和spring“不對應用程式類作任何限制”的理論相符合的。

  而像BeanPostProcessor這類的後處理器介面則不一樣,它不要求bean去繼承它,而是完全像外掛一樣註冊到spring容器中,為容器提供額外的功能。spring充分利用了BeanPostProcessor對bean進行加工處理(SpringAOP以此為基礎,後面會細說)。

  spring作為ioc容器其核心功能就是管理bean的建立以及bean之間的依賴關係,再進一步就是說spring管理bean的整個生命週期,從例項化到初始化,再到快取建立好的bean以及銷燬bean。在這個過程中,spring提供了多種方式(如上所述),使得使用者可以在bean的整個生命週期中方便地做一些自定義的操作。這也是spring中體現出來的一種優秀的設計方法論,easy to change,對擴充套件開放。

 

&n