Spring Bean作用域與生命周期深入講解
1.作用域定義
限定程序中變量的可用范圍叫做作用域,或者說(shuō)在源代碼中定義變量的某個(gè)區(qū)域就叫做作用域。
Bean 的作用域
而 Bean 的作用域是指 Bean 在 Spring 整個(gè)框架中的某種行為模式,比如 singleton 單例作用域,就表示 Bean 在整個(gè) Spring 中只有一份,它是全局共享的,那么當(dāng)其他人修改了這個(gè)值之后,那么另一個(gè)人讀取到的就是被修改的值。
Bean 的 6 種作用域
Spring 容器在初始化一個(gè) Bean 的實(shí)例時(shí),同時(shí)會(huì)指定該實(shí)例的作用域。Spring有 6 種作用域,最后四種是基于 Spring MVC 生效的:
- singleton:?jiǎn)卫饔糜颍J(rèn)作用域)
- prototype:原型作用域(多例作用域)
- request:請(qǐng)求作用域
- session:回話作用域
- application:全局作用域
- websocket:HTTP WebSocket 作用域
注意后 4 種狀態(tài)是 Spring MVC 中的值,在普通的 Spring 項(xiàng)目中只有前兩種。
1,2為Spring普通項(xiàng)目(Spring Core) 3,4,5為Spring MVC 6屬于Spring WebSocket
singleton
- 官方說(shuō)明:(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
- 描述:該作用域下的Bean在IoC容器中只存在一個(gè)實(shí)例:獲取Bean(即通過(guò)applicationContext.getBean等方法獲?。┘把b配Bean(即通過(guò)@Autowired注入)都是同一個(gè)對(duì)象。
- 場(chǎng)景:通常無(wú)狀態(tài)的Bean使用該作用域。無(wú)狀態(tài)表示Bean對(duì)象的屬性狀態(tài)不需要更新
- 備注:Spring默認(rèn)選擇該作用域
prototype
- 官方說(shuō)明:Scopes a single bean definition to any number of object instances.
- 描述:每次對(duì)該作用域下的Bean的請(qǐng)求都會(huì)創(chuàng)建新的實(shí)例:獲取Bean(即通過(guò)applicationContext.getBean等方法獲?。┘把b配Bean(即通過(guò)@Autowired注入)都是新的對(duì)象實(shí)例。
- 場(chǎng)景:通常有狀態(tài)的Bean使用該作用域
request
- 官方說(shuō)明:Scopes a single bean definition to the lifecycle of a single HTTP request. Thatis, each HTTP request has its own instance of a bean created off the back of a singlebean definition. Only valid in the context of a web-aware Spring ApplicationContext.
- 描述:每次http請(qǐng)求會(huì)創(chuàng)建新的Bean實(shí)例,類似于prototype
- 場(chǎng)景:一次http的請(qǐng)求和響應(yīng)的共享Bean
- 備注:限定SpringMVC中使用
session
- 官方 說(shuō)明:Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
- 描述:在一個(gè)http session中,定義一個(gè)Bean實(shí)例
- 場(chǎng)景: 用戶回話的共享Bean, 如:記錄 一個(gè)用戶的登陸信息
- 備注:限定SpringMVC中使用
application(了解)
- 官方說(shuō)明:Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
- 描述:在一個(gè)http servlet Context中,定義一個(gè)Bean實(shí)例
- 場(chǎng)景:Web應(yīng) 的上下 信息, 如:記錄一個(gè)應(yīng)用的共享信息
- 備注:限定SpringMVC中使用
websocket(了解)
- 官方說(shuō)明:Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
- 描述:在一個(gè)HTTP WebSocket的 命周期中,定義一個(gè)Bean實(shí)例
- 場(chǎng)景:WebSocket的每次會(huì)話中,保存了一個(gè)Map結(jié)構(gòu)的頭信息,將用來(lái)包裹客戶端消息頭。第一次初始化后,直到WebSocket結(jié)束都是同一個(gè)Bean。
- 備注:限定Spring WebSocket中使用
單例作用域(singleton)和全局作用域(application)區(qū)別
singleton 是 Spring Core 的作用域;
application 是 Spring Web 中的作用域;
singleton 作 于 IoC 的容器, application 作 于 Servlet 容器。
2.設(shè)置作用域
使用@Scope
標(biāo)簽就可以聲明Bean的作用域,比如設(shè)置Bean的作用域
@Scope
標(biāo)簽可以修飾方法,也可以修飾類,@Scope
有兩種設(shè)置方式:
1.直接設(shè)置值:@Scope("prototype")
2.直接枚舉設(shè)置:@Scope("ConfigurableBeanFactory.SCOPE_PROTOTYPE")
3.Bean 原理分析
3.1 Bean(Spring)執(zhí)行流程
Bean 執(zhí)行 流程(Spring 執(zhí) 流程):?jiǎn)?dòng) Spring 容器 -> 實(shí)例化 Bean(分配內(nèi)存空間,從 到有) -> Bean 注冊(cè)到 Spring 中(存操作) -> 將 Bean 裝配到需要的類中(取操作)。
3.2 Bean生命周期
所謂的生命周期指的是一個(gè)對(duì)象從誕生到銷毀的整個(gè)生命過(guò)程,我們把這個(gè)過(guò)程就叫做一個(gè)對(duì)象的生命周期。
Bean 的生命周期分為以下 5 部分:
實(shí)例化 Bean(為 Bean 分配內(nèi)存空間)【實(shí)例化!=初始化;只是執(zhí)行分配內(nèi)存空間的功能】
設(shè)置屬性(Bean 注入和裝配)【執(zhí)行依賴類的注入A需要使用B的方法,先初始化并將B加載到當(dāng)前類】
Bean 初始化
- 實(shí)現(xiàn)了各種Aware 通知的方法,如BeanNameAware、BeanFactoryAware、ApplicationContextAware 的接口方法;
- 執(zhí)行BeanPostProcessor 初始化前置方法;
- 執(zhí)行
@PostConstruct
初始化方法,依賴注入操作之后被執(zhí)行; - 執(zhí)行指定的 init-method方法(如果有指定的話);
- 執(zhí)行BeanPostProcessor 初始化后置方法。
使用Bean
銷毀 Bean
銷毀容器的各種 法,如 @PreDestroy、DisposableBean 接口方法、destroy-method。
執(zhí)行流程如下圖所示:
實(shí)例化和初始化的區(qū)別
實(shí)例化和屬性設(shè)置是 Java 級(jí)別的系統(tǒng)“事件”,其操作過(guò)程不可人工干預(yù)和修改;而初始化是給開(kāi)發(fā)者提供的,可以在實(shí)例化之后,類加載完成之前進(jìn)行自定義“事件”處理。
生命流程的“故事”
Bean 的生命流程看似繁瑣,但咱們可以以生活中的場(chǎng)景來(lái)理解它,比如我們現(xiàn)在需要買一棟房子,那么我們的流程是這樣的:
- 先買房(實(shí)例化,從無(wú)到有);
- 裝修(設(shè)置屬性);
- 買家電,如洗衣機(jī)、冰箱、電視、空調(diào)等([各種]初始化);
- 入?。ㄊ褂?Bean);
- 賣出去(Bean 銷毀)。
生命周期演示:
package com.beans; import org.springframework.beans.factory.BeanNameAware; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class BeanLifeComponent implements BeanNameAware { @PostConstruct public void postConstruct() { System.out.println("執(zhí)行 PostConstruct()"); } public void init() { System.out.println("執(zhí)行 BeanLifeComponent init-method"); } public void destory() { System.out.println("執(zhí)行了 destory 方法"); } @PreDestroy public void preDestroy() { System.out.println("執(zhí)行:preDestroy()"); } public void setBeanName(String s) { System.out.println("執(zhí)行了 setBeanName 方法:" + s); } }
xml 配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:content="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 設(shè)置需要存儲(chǔ)到 spring 中的 bean 根目錄 --> <content:component-scan base-package="com.beans"></content:component-scan> <bean id="beanlife" class="com.beans.BeanLifeComponent" init-method="init" destroy-method="destory"></bean> </beans>
調(diào)用類:
package com; import com.beans.BeanLifeComponent; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App2 { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class); System.out.println("執(zhí)行銷毀方法"); beanLifeComponent.destory(); // 執(zhí)行銷毀方法 } }
步驟 2 和步驟 3 的順序不能打個(gè)顛倒?。?!
到此這篇關(guān)于Spring Bean作用域與生命周期深入講解的文章就介紹到這了,更多相關(guān)Spring Bean作用域與生命周期內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談mybatis 樂(lè)觀鎖實(shí)現(xiàn),解決并發(fā)問(wèn)題
這篇文章主要介紹了淺談mybatis 樂(lè)觀鎖實(shí)現(xiàn),解決并發(fā)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08使用gRPC微服務(wù)的內(nèi)部通信優(yōu)化
這篇文章主要為大家介紹了微服務(wù)優(yōu)化之使用gRPC做微服務(wù)的內(nèi)部通信,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03Java幾個(gè)實(shí)例帶你進(jìn)階升華下篇
與其明天開(kāi)始,不如現(xiàn)在行動(dòng),本文為你帶來(lái)幾個(gè)Java書(shū)寫(xiě)的實(shí)際案例,對(duì)鞏固編程的基礎(chǔ)能力很有幫助,快來(lái)一起往下看看吧2022-03-03Java?EasyExcel利用填充模版動(dòng)態(tài)生成多個(gè)sheet頁(yè)
這篇文章主要為大家詳細(xì)介紹了Java?EasyExcel如何利用填充模版動(dòng)態(tài)生成多個(gè)sheet頁(yè),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12SpringMVC @RequestBody屬性名大寫(xiě)字母注入失敗的解決
這篇文章主要介紹了SpringMVC @RequestBody屬性名大寫(xiě)字母注入失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04Java數(shù)據(jù)結(jié)構(gòu)(線性表)詳解
本文主要介紹了Java數(shù)據(jù)結(jié)構(gòu)(線性表)的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01