<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Spring中Bean的生命周期是怎樣的?

jf_ro2CN3Fa ? 來源:樓仔 ? 作者:樓仔 ? 2022-10-11 15:08 ? 次閱讀

1. 基礎知識

1.1 什么是 IoC ?

1.2 Bean 生命周期

1.3 執行流程

1.4 擴展方法

2. 源碼解讀

2.1 代碼入口

2.2 實例化

2.3 屬性賦值

2.4 初始化

2.5 銷毀

3. 寫在最后

Spring Bean 的生命周期,面試時非常容易問,這不,前段時間就有個讀者去面試,因為不會回答這個問題,一面都沒有過。

如果只講基礎知識,感覺和網上大多數文章沒有區別,但是我又想寫得稍微深入一點。

考慮很多同學不喜歡看源碼,我就把文章分為 2 大部分,前面是基礎知識,主要方便大家面試和學習 ,后面是源碼部分,對源碼感興趣的同學可以繼續往后面看。

不 BB,上文章目錄。

f4755436-4162-11ed-96c9-dac502259ad0.png

1. 基礎知識

1.1 什么是 IoC ?

IoC,控制反轉,想必大家都知道,所謂的控制反轉,就是把 new 對象的權利交給容器,所有的對象都被容器控制,這就叫所謂的控制反轉。

IoC 很好地體現了面向對象設計法則之一 —— 好萊塢法則:“別找我們,我們找你 ”,即由 IoC 容器幫對象找相應的依賴對象并注入,而不是由對象主動去找。

理解好 IoC 的關鍵是要明確 “誰控制誰,控制什么,為何是反轉(有反轉就應該有正轉了),哪些方面反轉了”。

f4936020-4162-11ed-96c9-dac502259ad0.png

誰控制誰,控制什么?

傳統 Java SE 程序設計,我們直接在對象內部通過 new 進行創建對象,是程序主動去創建依賴對象。而 IoC 是由專門一個容器來創建這些對象,即由 IoC 容器來控制對象的創建。

誰控制誰?當然是 IoC 容器控制了對象;

控制什么?主要控制了外部資源獲?。ú恢皇菍ο?,比如包括文件等)。

為何是反轉,哪些方面反轉了?

有反轉就有正轉,傳統應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉,而反轉則是由容器來幫忙創建及注入依賴對象。

為何是反轉?因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉;

哪些方面反轉了?依賴對象的獲取被反轉了。

1.2 Bean 生命周期

對 Prototype Bean 來說,當用戶 getBean 獲得 Prototype Bean 的實例后,IOC 容器就不再對當前實例進行管理,而是把管理權交由用戶,此后再 getBean 生成的是新的實例。

所以我們描述 Bean 的生命周期,都是指的 Singleton Bean。

f51a6804-4162-11ed-96c9-dac502259ad0.png

Bean 生命周期過程:

實例化 :第 1 步,實例化一個 Bean 對象;

屬性賦值 :第 2 步,為 Bean 設置相關屬性和依賴;

初始化 :初始化的階段的步驟比較多,5、6 步是真正的初始化,第 3、4 步為在初始化前執行,第 7 步在初始化后執行,初始化完成之后,Bean 就可以被使用了;

銷毀 :第 8~10 步,第 8 步其實也可以算到銷毀階段,但不是真正意義上的銷毀,而是先在使用前注冊了銷毀的相關調用接口,為了后面第 9、10 步真正銷毀 Bean 時再執行相應的方法。

整個執行流程稍微有些抽象,下面我們通過代碼,來演示執行流程。

1.3 執行流程

創建一個 LouzaiBean。

publicclassLouzaiBeanimplementsInitializingBean,BeanFactoryAware,BeanNameAware,DisposableBean{

/**
*姓名
*/
privateStringname;

publicLouzaiBean(){
System.out.println("1.調用構造方法:我出生了!");
}

publicStringgetName(){
returnname;
}

publicvoidsetName(Stringname){
this.name=name;
System.out.println("2.設置屬性:我的名字叫"+name);
}

@Override
publicvoidsetBeanName(Strings){
System.out.println("3.調用BeanNameAware#setBeanName方法:我要上學了,起了個學名");
}

@Override
publicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{
System.out.println("4.調用BeanFactoryAware#setBeanFactory方法:選好學校了");
}

@Override
publicvoidafterPropertiesSet()throwsException{
System.out.println("6.InitializingBean#afterPropertiesSet方法:入學登記");
}

publicvoidinit(){
System.out.println("7.自定義init方法:努力上學ing");
}

@Override
publicvoiddestroy()throwsException{
System.out.println("9.DisposableBean#destroy方法:平淡的一生落幕了");
}

publicvoiddestroyMethod(){
System.out.println("10.自定義destroy方法:睡了,別想叫醒我");
}

publicvoidwork(){
System.out.println("Bean使用中:工作,只有對社會沒有用的人才放假。。");
}
}

自定義一個后處理器 MyBeanPostProcessor。

publicclassMyBeanPostProcessorimplementsBeanPostProcessor{

@Override
publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{
System.out.println("5.BeanPostProcessor.postProcessBeforeInitialization方法:到學校報名啦");
returnbean;
}

@Override
publicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{
System.out.println("8.BeanPostProcessor#postProcessAfterInitialization方法:終于畢業,拿到畢業證啦!");
returnbean;
}
}

applicationContext.xml 配置文件(部分)。





測試入口:

publicclassMyTest{
publicstaticvoidmain(String[]args){
ApplicationContextcontext=newClassPathXmlApplicationContext("classpath:applicationContext.xml");
LouzaiBeanlouzaiBean=(LouzaiBean)context.getBean("louzaiBean");
louzaiBean.work();
((ClassPathXmlApplicationContext)context).destroy();
}
}

執行結果:

1.調用構造方法:我出生了!
2.設置屬性:我的名字叫樓仔
3.調用BeanNameAware#setBeanName方法:我要上學了,起了個學名
4.調用BeanFactoryAware#setBeanFactory方法:選好學校了
5.BeanPostProcessor.postProcessBeforeInitialization方法:到學校報名啦
6.InitializingBean#afterPropertiesSet方法:入學登記
7.自定義init方法:努力上學ing
8.BeanPostProcessor#postProcessAfterInitialization方法:終于畢業,拿到畢業證啦!
Bean使用中:工作,只有對社會沒有用的人才放假。。
9.DisposableBean#destroy方法:平淡的一生落幕了
10.自定義destroy方法:睡了,別想叫醒我

這個流程非常清晰,Bean 生命周期流程圖能完全對應起來。

1.4 擴展方法

我們發現,整個生命周期有很多擴展過程,大致可以分為 4 類:

Aware 接口:讓 Bean 能拿到容器的一些資源,例如 BeanNameAware 的 setBeanName() ,BeanFactoryAware 的 setBeanFactory() ;

后處理器:進行一些前置和后置的處理,例如 BeanPostProcessor 的 postProcessBeforeInitialization()postProcessAfterInitialization() ;

生命周期接口:定義初始化方法和銷毀方法的,例如 InitializingBean 的 afterPropertiesSet() ,以及 DisposableBean 的 destroy() ;

配置生命周期方法:可以通過配置文件,自定義初始化和銷毀方法,例如配置文件配置的 init()destroyMethod() 。

2. 源碼解讀

注意:Spring 的版本是 5.2.15.RELEASE ,否則和我的代碼不一樣?。?!

上面的知識,網上其實都有,下面才是我們的重頭戲,讓你跟著我走一遍代碼流程。

2.1 代碼入口

f52ef8d2-4162-11ed-96c9-dac502259ad0.pngf5592b2a-4162-11ed-96c9-dac502259ad0.png

這里需要多跑幾次,把前面的 beanName 跳過去,只看 louzaiBean。

f58a2bc6-4162-11ed-96c9-dac502259ad0.pngf5c39cc6-4162-11ed-96c9-dac502259ad0.png

進入 doGetBean(),從 getSingleton() 沒有找到對象,進入創建 Bean 的邏輯。

f5ded540-4162-11ed-96c9-dac502259ad0.pngf614cd62-4162-11ed-96c9-dac502259ad0.png

2.2 實例化

進入 doCreateBean() 后,調用 createBeanInstance()。

f628265a-4162-11ed-96c9-dac502259ad0.png

進入 createBeanInstance() 后,調用 instantiateBean()。

f63fbda6-4162-11ed-96c9-dac502259ad0.pngf65af058-4162-11ed-96c9-dac502259ad0.pngf6687e58-4162-11ed-96c9-dac502259ad0.pngf68253fa-4162-11ed-96c9-dac502259ad0.pngf6b7d0de-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,實例化 LouzaiBean。

f6ca7ec8-4162-11ed-96c9-dac502259ad0.png圖片

2.3 屬性賦值

再回到 doCreateBean(),繼續往后走,進入 populateBean()。

這個方法非常重要,里面其實就是依賴注入的邏輯,不過這個不是我們今天的重點,大家如果對依賴注入和循環依賴感興趣,可以翻閱我之前的文章。

f6e63e56-4162-11ed-96c9-dac502259ad0.png

進入 populateBean() 后,執行 applyPropertyValues()

f701bd5c-4162-11ed-96c9-dac502259ad0.png

進入 applyPropertyValues(),執行 bw.setPropertyValues()

f70dedfc-4162-11ed-96c9-dac502259ad0.pngf737e12a-4162-11ed-96c9-dac502259ad0.pngf75d67a6-4162-11ed-96c9-dac502259ad0.pngf76e0f84-4162-11ed-96c9-dac502259ad0.png

進入 processLocalProperty(),執行 ph.setValue()。

f787e59e-4162-11ed-96c9-dac502259ad0.pngf7b03ee0-4162-11ed-96c9-dac502259ad0.pngf7cf9e52-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,給 LouzaiBean 賦值 name。

f7fd9c6c-4162-11ed-96c9-dac502259ad0.png

到這里,populateBean() 就執行完畢,下面開始初始化 Bean。

2.4 初始化

我們繼續回到 doCreateBean(),往后執行 initializeBean()。

f82a1116-4162-11ed-96c9-dac502259ad0.pngf847984e-4162-11ed-96c9-dac502259ad0.pngf8594698-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,給 LouzaiBean 設置 BeanName。

f873cdba-4162-11ed-96c9-dac502259ad0.png

回到 invokeAwareMethods()。

f8814026-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,給 LouzaiBean 設置 BeanFactory。

f8e5b308-4162-11ed-96c9-dac502259ad0.png

第一次回到 initializeBean() ,執行下面邏輯。

f8f35ff8-4162-11ed-96c9-dac502259ad0.png

這里需要多循環幾次,找到 MyBeanPostProcessor 的策略方法。

f93dad38-4162-11ed-96c9-dac502259ad0.png

我們自己定義的后置處理方法。

f988cc32-4162-11ed-96c9-dac502259ad0.png

第二次回到 initializeBean() ,執行下面邏輯。

f9b3dec2-4162-11ed-96c9-dac502259ad0.pngf9d8cf98-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,執行 afterPropertiesSet()。

f9f65ab8-4162-11ed-96c9-dac502259ad0.png

返回 invokeInitMethods(),執行下面邏輯。

fa1bbf24-4162-11ed-96c9-dac502259ad0.png

進入 invokeCustomInitMethod(),執行下面邏輯。

fa45b18a-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,執行 init()。

fa716384-4162-11ed-96c9-dac502259ad0.png

第三次回到 initializeBean() ,執行下面邏輯。

fa8e46ca-4162-11ed-96c9-dac502259ad0.pngfaa8e7a0-4162-11ed-96c9-dac502259ad0.png

我們自己定義的后置處理方法。

fb2152da-4162-11ed-96c9-dac502259ad0.png

到這里,初始化的流程全部結束,都是圍繞 initializeBean() 展開。

2.5 銷毀

當 louzaiBean 生成后,后面開始執行銷毀操作,整個流程就比較簡單。

fb47debe-4162-11ed-96c9-dac502259ad0.pngfb5f720e-4162-11ed-96c9-dac502259ad0.pngfb80dbba-4162-11ed-96c9-dac502259ad0.pngfba80762-4162-11ed-96c9-dac502259ad0.pngfbcf11b8-4162-11ed-96c9-dac502259ad0.pngfbf49f1e-4162-11ed-96c9-dac502259ad0.pngfc20e506-4162-11ed-96c9-dac502259ad0.pngfc3fcb38-4162-11ed-96c9-dac502259ad0.pngfc6ac6b2-4162-11ed-96c9-dac502259ad0.pngfc820aac-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,執行 destroy()。

fca82fb6-4162-11ed-96c9-dac502259ad0.png

回到 destroy(),執行下面邏輯。

fcc53da4-4162-11ed-96c9-dac502259ad0.pngfcfc5582-4162-11ed-96c9-dac502259ad0.pngfd9e5bac-4162-11ed-96c9-dac502259ad0.png

走進示例 LouzaiBean 的方法,執行 destroyMethod()。

fdd07268-4162-11ed-96c9-dac502259ad0.png

到這里,所有的流程全部結束,文章詳細描述所有的代碼邏輯流轉,你可以完全根據上面的邏輯,自己 debug 一遍。

3. 寫在最后

我們再回顧一下幾個重要的方法:

doCreateBean() :這個是入口;

createBeanInstance() :用來初始化 Bean,里面會調用對象的構造方法;

populateBean() :屬性對象的依賴注入,以及成員變量初始化;

initializeBean() :里面有 4 個方法,

先執行 aware 的 BeanNameAware、BeanFactoryAware 接口;

再執行 BeanPostProcessor 前置接口;

然后執行 InitializingBean 接口,以及配置的 init();

最后執行 BeanPostProcessor 的后置接口。

destory() :先執行 DisposableBean 接口,再執行配置的 destroyMethod()。

對于 populateBean(),里面的核心其實是對象的依賴注入,這里也是??嫉闹R點,比如循環依賴,大家如果對這塊也感興趣,可以和我交流。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JAVA
    +關注

    關注

    19

    文章

    2908

    瀏覽量

    103128
  • 編程
    +關注

    關注

    88

    文章

    3444

    瀏覽量

    92625
  • spring
    +關注

    關注

    0

    文章

    333

    瀏覽量

    14181
  • IOC
    IOC
    +關注

    關注

    0

    文章

    28

    瀏覽量

    10054

原文標題:阿里云面試:Spring 中 Bean 的生命周期是怎樣的?

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    基于Rust語言中的生命周期

    Rust是一門系統級編程語言具備高效、安和并發等特,而生命周期是這門語言中比較重要的概念之一。在這篇教程中,我們會了解什么是命周期、為什么需要生命周期、如何使用生命周期,同時我們依然會
    的頭像 發表于 09-19 17:03 ?630次閱讀

    Spring-10-bean生命周期

    spring
    電子學習
    發布于 :2023年01月07日 16:48:18

    09-SpringBean生命周期總結

    spring
    電子學習
    發布于 :2023年01月14日 09:55:54

    AutoScaling 生命周期掛鉤功能

    實例是伸縮組彈出來的不是手動添加的),然后釋放實例(如果 ECS 實例是伸縮組彈出來的不是手動添加的),并將實例從伸縮組移出。LifecycleHook 通知方式如果生命周期掛鉤配置了通知對象,那么
    發表于 06-27 17:13

    理解數據生命周期管理思路

    數據生命周期管理的思考
    發表于 03-17 10:49

    HarmonyOS應用開發-PageAbility生命周期

    pageAbility的生命周期如下圖所示:在代碼通過調用下列方法實現生命周期操作:onShow() :Ability由后臺不可見狀態切換到前臺可見狀態調用onShow方法,此時用戶在屏幕可以看到
    發表于 10-17 11:11

    在S32G2 RM中有“生命周期”,生命周期的完整含義是什么?

    在S32G2 RM,有“生命周期”。生命周期的完整含義是什么,我們應該如何使用它?
    發表于 04-23 10:37

    貫穿于全生命周期的功能安全

    簡要介紹了功能安全在SIS 全安全生命周期的主要活動,敘述了全生命周期的功能安全管理。簡要闡述了貫穿于整體安全生命周期的功能安全進行的主要階段,同時提出了在設計SIS
    發表于 12-19 15:50 ?15次下載

    貫穿于全生命周期的功能安全

    簡要介紹了功能安全在SIS 全安全生命周期的主要活動,敘述了全生命周期的功能安全管理。簡要闡述了貫穿于整體安全生命周期的功能安全進行的主要階段,同時提出了在設計SIS 時
    發表于 01-06 17:11 ?6次下載

    一文讀懂Android Activity生命周期

    正常情況下Activity的生命周期: Activity的生命周期大概可以歸為三部分 整個的生命周期:onCreate()可以設置所有的“全局”狀態, onDestory()可以釋放所有的資源 可見
    發表于 05-30 01:03 ?1395次閱讀

    Synopsys 啟動硅生命周期管理計劃

    Synopsis 的數據分析驅動的硅生命周期管理計劃解決了 IC 生命周期中的質量、可靠性和安全挑戰。
    發表于 08-18 15:37 ?654次閱讀
    Synopsys 啟動硅<b class='flag-5'>生命周期</b>管理計劃

    Vue入門Vue的生命周期

    .生命周期 4.1生命周期是什么 Vue的生命周期, 就是Vue實例從創建到銷毀的過程.
    的頭像 發表于 02-06 16:16 ?679次閱讀
    Vue入門Vue的<b class='flag-5'>生命周期</b>

    編譯器的標準生命周期

    編譯器的標準生命周期
    發表于 03-14 19:06 ?0次下載
    編譯器的標準<b class='flag-5'>生命周期</b>

    編譯器的標準生命周期

    編譯器的標準生命周期
    發表于 07-05 19:32 ?0次下載
    編譯器的標準<b class='flag-5'>生命周期</b>

    數據包的生命周期

    電子發燒友網站提供《數據包的生命周期.pdf》資料免費下載
    發表于 10-13 14:44 ?0次下載
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>