深入了解Spring中Bean的作用域和生命周期
作用域的種類
Spring 容器在初始化一個 Bean 的實(shí)例時,同時會指定該實(shí)例的作用域。Spring3 為 Bean 定義了五種作用域,具體如下。
1)singleton
單例模式,使用 singleton 定義的 Bean 在 Spring 容器中只有一個實(shí)例,這也是 Bean 默認(rèn)的作用域。
2)prototype
原型模式,每次通過 Spring 容器獲取 prototype 定義的 Bean 時,容器都將創(chuàng)建一個新的 Bean 實(shí)例。
3)request
在一次 HTTP 請求中,容器會返回該 Bean 的同一個實(shí)例。而對不同的 HTTP 請求,會返回不同的實(shí)例,該作用域僅在當(dāng)前 HTTP Request 內(nèi)有效。
4)session
在一次 HTTP Session 中,容器會返回該 Bean 的同一個實(shí)例。而對不同的 HTTP 請求,會返回不同的實(shí)例,該作用域僅在當(dāng)前 HTTP Session 內(nèi)有效。
5)global Session
在一個全局的 HTTP Session 中,容器會返回該 Bean 的同一個實(shí)例。該作用域僅在使用 portlet context 時有效。
在上述五種作用域中,singleton 和 prototype 是最常用的兩種,接下來將對這兩種作用域進(jìn)行詳細(xì)講解。
singleton 作用域
singleton 是 Spring 容器默認(rèn)的作用域,當(dāng)一個 Bean 的作用域?yàn)?singleton 時,Spring 容器中只會存在一個共享的 Bean 實(shí)例,并且所有對 Bean 的請求,只要 id 與該 Bean 定義相匹配,就只會返回 Bean 的同一個實(shí)例。
通常情況下,這種單例模式對于無會話狀態(tài)的 Bean(如 DAO 層、Service 層)來說,是最理想的選擇。
在 Spring 配置文件中,可以使用 <bean> 元素的 scope 屬性,將 Bean 的作用域定義成 singleton,其配置方式如下所示:
<bean id="person" class="com.mengma.scope.Person" scope="singleton"/>
在項(xiàng)目的 src 目錄下創(chuàng)建一個名為 com.mengma.scope 的包,在該包下創(chuàng)建 Person 類,類中不需要添加任何成員,然后創(chuàng)建 Spring 的配置文件 applicationContext.xml,將上述 Bean 的定義方式寫入配置文件中,最后創(chuàng)建一個名為 PersonTest 的測試類,編輯后如下所示。
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進(jìn)行實(shí)例化
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
xmlPath);
// 輸出獲得實(shí)例
System.out.println(applicationContext.getBean("person"));
System.out.println(applicationContext.getBean("person"));
}
}
使用 JUnit 測試運(yùn)行 test() 方法,運(yùn)行成功后,控制臺的輸出結(jié)果如圖 1 所示。

圖 1 輸出結(jié)果
從圖 1 中可以看到,兩次輸出的結(jié)果相同,這說明 Spring 容器只創(chuàng)建了一個 Person 類的實(shí)例。由于 Spring 容器默認(rèn)作用域是 singleton,如果不設(shè)置 scope="singleton",則其輸出結(jié)果也將是一個實(shí)例。
prototype 作用域
使用 prototype 作用域的 Bean 會在每次請求該 Bean 時都會創(chuàng)建一個新的 Bean 實(shí)例。因此對需要保持會話狀態(tài)的 Bean(如 Struts2 的 Action 類)應(yīng)該使用 prototype 作用域。
在 Spring 配置文件中,要將 Bean 定義為 prototype 作用域,只需將 <bean> 元素的 scope 屬性值定義成 prototype,其示例代碼如下所示:
<bean id="person" class="com.mengma.scope.Person" scope="prototype"/>
將《singleton作用域》部分中的配置文件更改成上述代碼形式后,再次運(yùn)行 test() 方法,控制臺的輸出結(jié)果如圖 2 所示。

圖 2 輸出結(jié)果
從圖 2 的輸出結(jié)果中可以看到,兩次輸出的結(jié)果并不相同,這說明在 prototype 作用域下,Spring 容器創(chuàng)建了兩個不同的 Person 實(shí)例。
生命周期
而對于 prototype 作用域的 Bean,Spring 只負(fù)責(zé)創(chuàng)建,當(dāng)容器創(chuàng)建了 Bean 的實(shí)例后,Bean 的實(shí)例就交給客戶端代碼管理,Spring 容器將不再跟蹤其生命周期。每次客戶端請求 prototype 作用域的 Bean 時,Spring 容器都會創(chuàng)建一個新的實(shí)例,并且不會管那些被配置成 prototype 作用域的 Bean 的生命周期。
了解 Spring 生命周期的意義就在于,可以利用 Bean 在其存活期間的指定時刻完成一些相關(guān)操作。這種時刻可能有很多,但一般情況下,會在 Bean 被初始化后和被銷毀前執(zhí)行一些相關(guān)操作。
在 Spring 中,Bean 的生命周期是一個很復(fù)雜的執(zhí)行過程,我們可以利用 Spring 提供的方法定制 Bean 的創(chuàng)建過程。
當(dāng)一個 Bean 被加載到 Spring 容器時,它就具有了生命,而 Spring 容器在保證一個 Bean 能夠使用之前,會進(jìn)行很多工作。Spring 容器中 Bean 的生命周期流程如圖3所示。

圖3Bean 的生命周期
Bean 生命周期的整個執(zhí)行過程描述如下。
1)根據(jù)配置情況調(diào)用 Bean 構(gòu)造方法或工廠方法實(shí)例化 Bean。
2)利用依賴注入完成 Bean 中所有屬性值的配置注入。
3)如果 Bean 實(shí)現(xiàn)了 BeanNameAware 接口,則 Spring 調(diào)用 Bean 的 setBeanName() 方法傳入當(dāng)前 Bean 的 id 值。
4)如果 Bean 實(shí)現(xiàn)了 BeanFactoryAware 接口,則 Spring 調(diào)用 setBeanFactory() 方法傳入當(dāng)前工廠實(shí)例的引用。
5)如果 Bean 實(shí)現(xiàn)了 ApplicationContextAware 接口,則 Spring 調(diào)用 setApplicationContext() 方法傳入當(dāng)前 ApplicationContext 實(shí)例的引用。
6)如果 BeanPostProcessor 和 Bean 關(guān)聯(lián),則 Spring 將調(diào)用該接口的預(yù)初始化方法 postProcessBeforeInitialzation() 對 Bean 進(jìn)行加工操作,此處非常重要,Spring 的 AOP 就是利用它實(shí)現(xiàn)的。
7)如果 Bean 實(shí)現(xiàn)了 InitializingBean 接口,則 Spring 將調(diào)用 afterPropertiesSet() 方法。
8)如果在配置文件中通過 init-method 屬性指定了初始化方法,則調(diào)用該初始化方法。
9)如果 BeanPostProcessor 和 Bean 關(guān)聯(lián),則 Spring 將調(diào)用該接口的初始化方法 postProcessAfterInitialization()。此時,Bean 已經(jīng)可以被應(yīng)用系統(tǒng)使用了。
10)如果在 <bean> 中指定了該 Bean 的作用范圍為 scope="singleton",則將該 Bean 放入 Spring IoC 的緩存池中,將觸發(fā) Spring 對該 Bean 的生命周期管理;如果在 <bean> 中指定了該 Bean 的作用范圍為 scope="prototype",則將該 Bean 交給調(diào)用者,調(diào)用者管理該 Bean 的生命周期,Spring 不再管理該 Bean。
11)如果 Bean 實(shí)現(xiàn)了 DisposableBean 接口,則 Spring 會調(diào)用 destory() 方法將 Spring 中的 Bean 銷毀;如果在配置文件中通過 destory-method 屬性指定了 Bean 的銷毀方法,則 Spring 將調(diào)用該方法對 Bean 進(jìn)行銷毀。
Spring 為 Bean 提供了細(xì)致全面的生命周期過程,通過實(shí)現(xiàn)特定的接口或 <bean> 的屬性設(shè)置,都可以對 Bean 的生命周期過程產(chǎn)生影響。雖然可以隨意配置 <bean> 的屬性,但是建議不要過多地使用 Bean 實(shí)現(xiàn)接口,因?yàn)檫@樣會導(dǎo)致代碼和 Spring 的聚合過于緊密。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 詳解Spring中Bean的生命周期和作用域及實(shí)現(xiàn)方式
- 淺談Spring中Bean的作用域、生命周期
- Spring實(shí)戰(zhàn)之Bean的作用域request用法分析
- Spring實(shí)戰(zhàn)之Bean的作用域singleton和prototype用法分析
- spring ioc的簡單實(shí)例及bean的作用域?qū)傩越馕?/a>
- JSP 中Spring Bean 的作用域詳解
- 簡單了解spring bean作用域?qū)傩詓ingleton和prototype的區(qū)別
- Spring中Bean的作用域與生命周期詳解
- 詳解Spring中Bean的作用域與生命周期
- Spring?框架中的?Bean?作用域(Scope)使用詳解
相關(guān)文章
Springboot jar包 idea 遠(yuǎn)程調(diào)試的操作過程
文章介紹了如何在IntelliJ IDEA中遠(yuǎn)程調(diào)試Spring Boot項(xiàng)目的Jar包,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-11-11
java使用PDFRenderer實(shí)現(xiàn)預(yù)覽PDF功能
這篇文章主要為大家詳細(xì)介紹了java使用PDFRenderer實(shí)現(xiàn)預(yù)覽PDF功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12
SpringBoot常見get/post請求參數(shù)處理、參數(shù)注解校驗(yàn)及參數(shù)自定義注解校驗(yàn)詳解
這篇文章主要給大家介紹了關(guān)于SpringBoot常見get/post請求參數(shù)處理、參數(shù)注解校驗(yàn)及參數(shù)自定義注解校驗(yàn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03
Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之環(huán)形鏈表
無論是靜態(tài)鏈表還是動態(tài)鏈表,有時在解決具體問題時,需要我們對其結(jié)構(gòu)進(jìn)行稍微地調(diào)整。比如,可以把鏈表的兩頭連接,使其成為了一個環(huán)狀鏈表,通常稱為循環(huán)鏈表2022-02-02
Springboot中路徑參數(shù)帶 (%2F)的問題徹底解決方案
這篇文章主要介紹了徹底解決Springboot中路徑參數(shù)帶(%2F)的問題,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06
BufferedWriter如何使用write方法實(shí)現(xiàn)換行
這篇文章主要介紹了BufferedWriter如何使用write方法實(shí)現(xiàn)換行的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
使用SpringBoot跨系統(tǒng)調(diào)用接口的方案
這篇文章主要介紹了使用SpringBoot跨系統(tǒng)調(diào)用接口的方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
Docker搭建前端Java的開發(fā)環(huán)境詳解
相信每個人入職第一天就是搭建本地開發(fā)環(huán)境,因?yàn)槲宜居玫氖莏ava,看見了多年不見的eclipse的圖標(biāo)出現(xiàn)我的電腦上,我是難過的。后來知道并不是我一個人有此感受。這篇文章是為了解決前后端開發(fā)沒有徹底分離的坑,詳細(xì)的給大家介紹了利用Docker搭建前端Java的開發(fā)環(huán)境。2016-10-10
java并發(fā)容器ConcurrentHashMap深入分析
這篇文章主要為大家介紹了java并發(fā)容器ConcurrentHashMap使用示例及深入分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05

