1. 程式人生 > >Spring Bean生命周期

Spring Bean生命周期

-i 有一個 自定義 factory actor prope width ava 對象銷毀

概述

對於普通的Java對象,當new的時候創建對象,當它沒有任何引用的時候被垃圾回收機制回收。而由Spring IoC容器托管的對象,它們的生命周期完全由容器控制。Spring中每個Bean的生命周期如下:

技術分享圖片

1. 實例化Bean

對於BeanFactory容器,當客戶向容器請求一個尚未初始化的bean時,或初始化bean的時候需要註入另一個尚未初始化的依賴時,容器就會調用createBean進行實例化。

對於ApplicationContext容器,當容器啟動結束後,便實例化所有的bean。

容器通過獲取BeanDefinition對象中的信息進行實例化。並且這一步僅僅是簡單的實例化,並未進行依賴註入。

實例化對象被包裝在BeanWrapper對象中,BeanWrapper提供了設置對象屬性的接口,從而避免了使用反射機制設置屬性。

2. 設置對象屬性(依賴註入)

實例化後的對象被封裝在BeanWrapper對象中,並且此時對象仍然是一個原生的狀態,並沒有進行依賴註入。

緊接著,Spring根據BeanDefinition中的信息進行依賴註入。

並且通過BeanWrapper提供的設置屬性的接口完成依賴註入。

3. 註入Aware接口

緊接著,Spring會檢測該對象是否實現了xxxAware接口,並將相關的xxxAware實例註入給bean。

4. BeanPostProcessor

當經過上述幾個步驟後,bean對象已經被正確構造,但如果你想要對象被使用前再進行一些自定義的處理,就可以通過BeanPostProcessor接口實現。

該接口提供了兩個函數:

  • postProcessBeforeInitialzation( Object bean, String beanName ) 當前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。這個函數會先於InitialzationBean執行,因此稱為前置處理。所有Aware接口的註入就是在這一步完成的。
  • postProcessAfterInitialzation( Object bean, String beanName ) 當前正在初始化的bean對象會被傳遞進來,我們就可以對這個bean作任何處理。這個函數會在InitialzationBean完成後執行,因此稱為後置處理。

5. InitializingBean與init-method

當BeanPostProcessor的前置處理完成後就會進入本階段。

InitializingBean接口只有一個函數:afterPropertiesSet()

這一階段也可以在bean正式構造完成前增加我們自定義的邏輯,但它與前置處理不同,由於該函數並不會把當前bean對象傳進來,因此在這一步沒辦法處理對象本身,只能增加一些額外的邏輯。

若要使用它,我們需要讓bean實現該接口,並把要增加的邏輯寫在該函數中。然後Spring會在前置處理完成後檢測當前bean是否實現了該接口,並執行afterPropertiesSet函數。

當然,Spring為了降低對客戶代碼的侵入性,給bean的配置提供了init-method屬性,該屬性指定了在這一階段需要執行的函數名。Spring便會在初始化階段執行我們設置的函數。

init-method本質上仍然使用了InitializingBean接口。

6. DisposableBean和destroy-method

和init-method一樣,通過給destroy-method指定函數,就可以在bean銷毀前執行指定的邏輯。

其他

其實很多時候我們並不會真的去實現上面說描述的那些接口,所以下面針對bean的單例和非單例來描述下bean的生命周期。

單例管理的對象

當scope=”singleton”,即默認情況下,會在啟動容器時(即實例化容器時)時實例化。但我們可以指定Bean節點的lazy-init=”true”來延遲初始化bean,這時候,只有在第一次獲取bean時才會初始化bean,即第一次請求該bean時才初始化。

在創建對象的時候先調用構造器,然後調用 init-method 屬性值中所指定的方法。

對象在被銷毀的時候,會調用 destroy-method 屬性值中所指定的方法(例如調用Container.destroy()方法的時候)。


非單例管理的對象

當scope=”prototype”時,容器也會延遲初始化 bean。Spring 會在第一次請求該 bean 時才初始化(如調用getBean方法時)。

在第一次請求每一個 prototype 的bean 時,Spring容器都會調用其構造器創建這個對象,然後調用init-method屬性值中所指定的方法。

對象銷毀的時候,Spring 容器不會幫我們調用任何方法,因為是非單例,這個類型的對象有很多個,Spring容器一旦把這個對象交給你之後,就不再管理這個對象了。

對於 prototype 作用域的 bean,有一點非常重要,那就是 Spring不能對一個 prototype bean 的整個生命周期負責:容器在初始化、配置、裝飾或者是裝配完一個prototype實例後,將它交給客戶端,隨後就對該prototype實例不聞不問了。 清除prototype作用域的對象並釋放任何prototype bean所持有的昂貴資源,都是客戶端代碼的職責(讓Spring容器釋放被prototype作用域bean占用資源的一種可行方式是,通過使用bean的後置處理器,該處理器持有要被清除的bean的引用)。

Spring Bean生命周期