Spring中Bean的做用域和生命週期

做用域的種類

Spring 容器在初始化一個 Bean 的實例時,同時會指定該實例的做用域。Spring3 爲 Bean 定義了五種做用域,具體以下。spring

1)singleton

單例模式,使用 singleton 定義的 Bean 在 Spring 容器中只有一個實例,這也是 Bean 默認的做用域。緩存

2)prototype

原型模式,每次經過 Spring 容器獲取 prototype 定義的 Bean 時,容器都將建立一個新的 Bean 實例。session

3)request

在一次 HTTP 請求中,容器會返回該 Bean 的同一個實例。而對不一樣的 HTTP 請求,會返回不一樣的實例,該做用域僅在當前 HTTP Request 內有效。app

4)session

在一次 HTTP Session 中,容器會返回該 Bean 的同一個實例。而對不一樣的 HTTP 請求,會返回不一樣的實例,該做用域僅在當前 HTTP Session 內有效。post

5)global Session

在一個全局的 HTTP Session 中,容器會返回該 Bean 的同一個實例。該做用域僅在使用 portlet context 時有效。

在上述五種做用域中,singleton 和 prototype 是最經常使用的兩種,接下來將對這兩種做用域進行詳細講解。測試

singleton 做用域

singleton 是 Spring 容器默認的做用域,當一個 Bean 的做用域爲 singleton 時,Spring 容器中只會存在一個共享的 Bean 實例,而且全部對 Bean 的請求,只要 id 與該 Bean 定義相匹配,就只會返回 Bean 的同一個實例。

一般狀況下,這種單例模式對於無會話狀態的 Bean(如 DAO 層、Service 層)來講,是最理想的選擇。

在 Spring 配置文件中,可使用 <bean> 元素的 scope 屬性,將 Bean 的做用域定義成 singleton,其配置方式以下所示:spa

<bean id="person" class="com.mengma.scope.Person" scope="singleton"/>

 

在項目的 src 目錄下建立一個名爲 com.mengma.scope 的包,在該包下建立 Person 類,類中不須要添加任何成員,而後建立 Spring 的配置文件 applicationContext.xml,將上述 Bean 的定義方式寫入配置文件中,最後建立一個名爲 PersonTest 的測試類,編輯後以下所示。.net

package com.mengma.scope; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class PersonTest { @Test public void test() { // 定義Spring配置文件路徑
String xmlPath = "com/mengma/scope/applicationContext.xml"; // 初始化Spring容器,加載配置文件,並對bean進行實例化
ApplicationContext applicationContext = new ClassPathXmlApplicationContext( xmlPath); // 輸出得到實例
System.out.println(applicationContext.getBean("person")); System.out.println(applicationContext.getBean("person")); } }

 

使用 JUnit 測試運行 test() 方法,運行成功後,控制檯的輸出結果如圖 1 所示。
prototype

輸出結果
圖 1  輸出結果


從圖 1 中能夠看到,兩次輸出的結果相同,這說明 Spring 容器只建立了一個 Person 類的實例。因爲 Spring 容器默認做用域是 singleton,若是不設置 scope="singleton",則其輸出結果也將是一個實例。3d

prototype 做用域

使用 prototype 做用域的 Bean 會在每次請求該 Bean 時都會建立一個新的 Bean 實例。所以對須要保持會話狀態的 Bean(如 Struts2 的 Action 類)應該使用 prototype 做用域。

在 Spring 配置文件中,要將 Bean 定義爲 prototype 做用域,只需將 <bean> 元素的 scope 屬性值定義成 prototype,其示例代碼以下所示:

<bean id="person" class="com.mengma.scope.Person" scope="prototype"/>

 

將《singleton做用域》部分中的配置文件更改爲上述代碼形式後,再次運行 test() 方法,控制檯的輸出結果如圖 2 所示。

輸出結果
圖 2  輸出結果


從圖 2 的輸出結果中能夠看到,兩次輸出的結果並不相同,這說明在 prototype 做用域下,Spring 容器建立了兩個不一樣的 Person 實例。

 

生命週期

 

而對於 prototype 做用域的 Bean,Spring 只負責建立,當容器建立了 Bean 的實例後,Bean 的實例就交給客戶端代碼管理,Spring 容器將再也不跟蹤其生命週期。每次客戶端請求 prototype 做用域的 Bean 時,Spring 容器都會建立一個新的實例,而且不會管那些被配置成 prototype 做用域的 Bean 的生命週期。

瞭解 Spring 生命週期的意義就在於,能夠利用 Bean 在其存活期間的指定時刻完成一些相關操做。這種時刻可能有不少,但通常狀況下,會在 Bean 被初始化後和被銷燬前執行一些相關操做。

在 Spring 中,Bean 的生命週期是一個很複雜的執行過程,咱們能夠利用 Spring 提供的方法定製 Bean 的建立過程。

當一個 Bean 被加載到 Spring 容器時,它就具備了生命,而 Spring 容器在保證一個 Bean 可以使用以前,會進行不少工做。Spring 容器中 Bean 的生命週期流程如圖 1 所示。

Bean的生命週期
圖 1  Bean 的生命週期

Bean 生命週期的整個執行過程描述以下。 1)根據配置狀況調用 Bean 構造方法或工廠方法實例化 Bean。 2)利用依賴注入完成 Bean 中全部屬性值的配置注入。 3)若是 Bean 實現了 BeanNameAware 接口,則 Spring 調用 Bean 的 setBeanName() 方法傳入當前 Bean 的 id 值。 4)若是 Bean 實現了 BeanFactoryAware 接口,則 Spring 調用 setBeanFactory() 方法傳入當前工廠實例的引用。 5)若是 Bean 實現了 ApplicationContextAware 接口,則 Spring 調用 setApplicationContext() 方法傳入當前 ApplicationContext 實例的引用。 6)若是 BeanPostProcessor 和 Bean 關聯,則 Spring 將調用該接口的預初始化方法 postProcessBeforeInitialzation() 對 Bean 進行加工操做,此處很是重要,Spring 的 AOP 就是利用它實現的。 7)若是 Bean 實現了 InitializingBean 接口,則 Spring 將調用 afterPropertiesSet() 方法。 8)若是在配置文件中經過 init-method 屬性指定了初始化方法,則調用該初始化方法。 9)若是 BeanPostProcessor 和 Bean 關聯,則 Spring 將調用該接口的初始化方法 postProcessAfterInitialization()。此時,Bean 已經能夠被應用系統使用了。 10)若是在 <bean> 中指定了該 Bean 的做用範圍爲 scope="singleton",則將該 Bean 放入 Spring IoC 的緩存池中,將觸發 Spring 對該 Bean 的生命週期管理;若是在 <bean> 中指定了該 Bean 的做用範圍爲 scope="prototype",則將該 Bean 交給調用者,調用者管理該 Bean 的生命週期,Spring 再也不管理該 Bean。 11)若是 Bean 實現了 DisposableBean 接口,則 Spring 會調用 destory() 方法將 Spring 中的 Bean 銷燬;若是在配置文件中經過 destory-method 屬性指定了 Bean 的銷燬方法,則 Spring 將調用該方法對 Bean 進行銷燬。 Spring 爲 Bean 提供了細緻全面的生命週期過程,經過實現特定的接口或 <bean> 的屬性設置,均可以對 Bean 的生命週期過程產生影響。雖然能夠隨意配置 <bean> 的屬性,可是建議不要過多地使用 Bean 實現接口,由於這樣會致使代碼和 Spring 的聚合過於緊密。

相關文章
相關標籤/搜索