天天看點

Spring Bean的生命周期管理(下)總結

Spring Bean的生命周期管理(下)總結

Aware接口是針對某個 實作這些接口的Bean 定制初始化的過程,

Spring還可針對容器中 所有Bean 或 某些Bean 定制初始化過程,隻需提供一個實作BeanPostProcessor接口的實作類。

該接口包含如下方法:

  • postProcessBeforeInitialization

    在容器中的Bean初始化之前執行

  • postProcessAfterInitialization

    在容器中的Bean初始化之後執行

執行個體

public class CustomerBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=" + beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("執行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);
        return bean;
    }
}      

要将BeanPostProcessor的Bean像其他Bean一樣定義在配置檔案中

<bean class="com.javaedge.spring.service.CustomerBeanPostProcessor"/>      

總結

Spring Bean的生命周期

Bean容器找到配置檔案中 Spring Bean 的定義。

Bean容器利用反射建立一個Bean的執行個體。

如果涉及到一些屬性值,利用set方法設定一些屬性值。

如果Bean實作了BeanNameAware接口,調用setBeanName()方法,傳入Bean的名字

如果Bean實作了BeanClassLoaderAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的執行個體

如果Bean實作了BeanFactoryAware接口,調用setBeanClassLoader()方法,傳入ClassLoader對象的執行個體

與上面的類似,如果實作了其他Aware接口,就調用相應的方法。

如果有和加載這個Bean的Spring容器相關的BeanPostProcessor對象,執行postProcessBeforeInitialization()方法

若Bean實作InitializingBean接口,執行afterPropertiesSet()

若Bean定義包含init-method屬性,執行指定方法

如果有和加載這個Bean的Spring容器相關的BeanPostProcessor對象,執行postProcessAfterInitialization()方法

當要銷毀Bean的時候,如果Bean實作了DisposableBean接口,執行destroy()方法。

當要銷毀Bean的時候,如果Bean在配置檔案中的定義包含destroy-method屬性,執行指定的方法。

Spring Bean的生命周期管理(下)總結
Spring Bean的生命周期管理(下)總結
Spring Bean的生命周期管理(下)總結
Spring Bean的生命周期管理(下)總結
Spring Bean的生命周期管理(下)總結
Spring Bean的生命周期管理(下)總結
Spring Bean的生命周期管理(下)總結

單例管理的對象

當scope=”singleton”,即預設情況下,會在啟動容器時(即執行個體化容器時)時執行個體化。但我們可以指定Bean節點的lazy-init=”true”來延遲初始化bean,這時候,隻有在第一次擷取bean時才會初始化bean,即第一次請求該bean時才初始化。如下配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>        

如果想對所有的預設單例bean都應用延遲初始化,可以在根節點beans設定default-lazy-init屬性為true,如下所示:

<beans default-lazy-init="true" …>      

預設情況下,Spring 在讀取 xml 檔案的時候,就會建立對象。在建立對象的時候先調用構造器,然後調用 init-method 屬性值中所指定的方法。對象在被銷毀的時候,會調用 destroy-method 屬性值中所指定的方法(例如調用Container.destroy()方法的時候)。寫一個測試類,代碼如下:

public class LifeBean {
    private String name;  

    public LifeBean(){  
        System.out.println("LifeBean()構造函數");  
    }  
    public String getName() {  
        return name;  
    }  

    public void setName(String name) {  
        System.out.println("setName()");  
        this.name = name;  
    }  

    public void init(){  
        System.out.println("this is init of lifeBean");  
    }  

    public void destory(){  
        System.out.println("this is destory of lifeBean " + this);  
    }  
}      

life.xml配置如下:

<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton" 
            init-method="init" destroy-method="destory" lazy-init="true"/>      

測試代碼:

public class LifeTest {
    @Test 
    public void test() {
        AbstractApplicationContext container = 
        new ClassPathXmlApplicationContext("life.xml");
        LifeBean life1 = (LifeBean)container.getBean("life");
        System.out.println(life1);
        container.close();
    }
}      

結果:

LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@573f2bb1
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1      

非單例管理的對象

當scope=”prototype”時,容器也會延遲初始化 bean,Spring 讀取xml 檔案的時候,并不會立刻建立對象,而是在第一次請求該 bean 時才初始化(如調用getBean方法時)。在第一次請求每一個 prototype 的bean 時,Spring容器都會調用其構造器建立這個對象,然後調用init-method屬性值中所指定的方法。對象銷毀的時候,Spring 容器不會幫我們調用任何方法,因為是非單例,這個類型的對象有很多個,Spring容器一旦把這個對象交給你之後,就不再管理這個對象了。

為了測試prototype bean的生命周期,life.xml配置如下:

<bean id="life_prototype" class="com.bean.LifeBean" scope="prototype" init-method="init" destroy-method="destory"/>      

測試程式:

public class LifeTest {
    @Test 
    public void test() {
        AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");
        LifeBean life1 = (LifeBean)container.getBean("life_singleton");
        System.out.println(life1);

        LifeBean life3 = (LifeBean)container.getBean("life_prototype");
        System.out.println(life3);
        container.close();
    }
}      

運作結果:

LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@573f2bb1
LifeBean()構造函數
this is init of lifeBean
com.bean.LifeBean@5ae9a829
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1      

可以發現,對于作用域為 prototype 的 bean ,其destroy方法并沒有被調用。如果 bean 的 scope 設為prototype時,當容器關閉時,destroy 方法不會被調用。對于 prototype 作用域的 bean,有一點非常重要,那就是 Spring不能對一個 prototype bean 的整個生命周期負責:容器在初始化、配置、裝飾或者是裝配完一個prototype執行個體後,将它交給用戶端,随後就對該prototype執行個體不聞不問了。 不管何種作用域,容器都會調用所有對象的初始化生命周期回調方法。但對prototype而言,任何配置好的析構生命周期回調方法都将不會被調用。清除prototype作用域的對象并釋放任何prototype bean所持有的昂貴資源,都是用戶端代碼的職責(讓Spring容器釋放被prototype作用域bean占用資源的一種可行方式是,通過使用bean的後置處理器,該處理器持有要被清除的bean的引用)。談及prototype作用域的bean時,在某些方面你可以将Spring容器的角色看作是Java new操作的替代者,任何遲于該時間點的生命周期事宜都得交由用戶端來處理。

Spring 容器可以管理 singleton 作用域下 bean 的生命周期,在此作用域下,Spring 能夠精确地知道bean何時被建立,何時初始化完成,以及何時被銷毀。而對于 prototype 作用域的bean,Spring隻負責建立,當容器建立了 bean 的執行個體後,bean 的執行個體就交給了用戶端的代碼管理,Spring容器将不再跟蹤其生命周期,并且不會管理那些被配置成prototype作用域的bean的生命周期。