亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于spring的@Bean注解放入引用Bean中初始化失敗分析

 更新時間:2023年07月21日 09:55:50   作者:孔天逸  
這篇文章主要介紹了關(guān)于spring的@Bean注解放入引用Bean中初始化失敗分析,Spring的@Bean注解用于告訴方法,產(chǎn)生一個Bean對象,然后這個Bean對象交給Spring管理,產(chǎn)生這個Bean對象的方法Spring只會調(diào)用一次,需要的朋友可以參考下

以下討論的問題及術(shù)語均在SpringBoot框架下,問題十分小眾,僅做整理記錄。

1. Bean依賴屬性

Bean依賴屬性的注入順序,與代碼定義順序無關(guān);

最好是將@Bean注解配置的Bean放在@Configuration注解修飾的專門用于配置的類中;

2. 問題背景

為了方便,將使用注解(@Bean)方法生成的Bean的方法體定義在了使用此Bean的類中

代碼結(jié)構(gòu)如下(為了描述方便,后文我們姑且將initBeanTestService叫做外層Bean,needInitBean叫做內(nèi)層Bean):

錯誤代碼

編寫單元測試

運行printInitBeanValue方法,并在方法體內(nèi)打斷點便于觀察屬性值,

單元測試:

單元測試

運行單元測試會發(fā)現(xiàn),通過內(nèi)層Bean的屬性值needInitValue的值為null,而外層Bean的屬性值needInitValue有值

說明在初始化needInitBean時,外層Bean的屬性值initValue并未注入成功,

運行結(jié)果:

測試結(jié)果

簡單理下思路,因為外層Bean的類通過@Service注解進行修飾,所以SpringBoot在啟動時會掃描到此注解進行Bean的初始化

初始化時會發(fā)現(xiàn)此Bean依賴initValueneeInitBean兩個屬性,讀配置拿到initValue的值

然后去容器中查找是否有needInitBean存在,顯然并不存在,于是要先初始化needInitBean,即內(nèi)層Bean;

內(nèi)層bean的初始化,依賴于外層bean的initValue屬性值

從現(xiàn)象來看,此時initValue無值,我們有以下疑問:

此initValue為什么沒有值?外層Bean按理說應(yīng)該已經(jīng)初始化一半了。

3. 調(diào)用棧追蹤

為了解釋上述問題1,我們在@Bean注解修飾的方法體內(nèi)打斷點,從內(nèi)層Bean的初始化開始,沿著斷點處的調(diào)用棧倒著追蹤,

1.首先是一些反射包下的方法;

2.一些BeanFactory初始化bean的方法;

3.找到AbstractBeanFactory中,發(fā)現(xiàn)此處開始創(chuàng)建needInitBean,那么上邊的調(diào)用方就是初始化此Bean的觸發(fā)點;

4.找到CommonAnnotationBeanPostProcessor,發(fā)現(xiàn)是此處為觸發(fā)點;

5.在CommonAnnotationBeanPostProcessor一番游歷,發(fā)現(xiàn)此處的邏輯是向外層Bean中注入依賴,找到319行,findResourceMetadata,此方法為找到需要注入的屬性或方法的元數(shù)據(jù),緊接著321行,為依賴注入邏輯(當(dāng)然,若依賴是Bean,則去BeanFactory請求,找不到則進行初始化);

注入

點進去findResourceMetadata方法看看他是咋找要注入的屬性的,包了一層緩存,主要邏輯在buildResourceMetadata方法,這里我們會發(fā)現(xiàn),他遍歷了各個屬性和方法,找到有特定注解的屬性和方法,放到了待注入的列表。其中注解就包括了我們熟悉的,也是外層bean中needInitBean頭上的@Resource。但是并沒有發(fā)現(xiàn)我們同樣熟悉的@Value@Autowire;

resource

6.繼續(xù)跟著調(diào)用棧往下走,到AbstractAutowireCaptableBeanFactory中,發(fā)現(xiàn)有一個循環(huán)去遍歷BeanPostProceccer, 并過濾出InstantiationAwareBeanPostProcessor,對創(chuàng)建中的Bean進行處理,展開BeanPostProceccer的列表,會發(fā)現(xiàn)我們上邊看到的CommonAnnotationBeanPostProcessor后邊還有個AutowiredAnnotationBeanPostProcessor,此類也繼承自InstantiationAwareBeanPostProcessor, 所以也會遍歷到,然后我們就會發(fā)現(xiàn)他與5中描述的邏輯類似,也是先找到需要注入的屬性,然后執(zhí)行注入。不同的是它解析@Value@Autowire注解的屬性為需要注入的屬性;

在這里插入圖片描述

7.上面提到的遍歷邏輯,是在對外層Bean進行依賴注入,即外層Bean的初始化過程,因為外層Bean是@Service注解修飾的,所以會在SpringBoot啟動時掃描到進行初始化

所以我們再往下走沒幾步就到了SpringApplication.run

4. 問題出現(xiàn)邏輯梳理

  1. 應(yīng)用啟動,掃描@Service注解修飾的外層Bean,對其進行初始化;
  2. Bean的初始化由若干實現(xiàn)InstantiationAwareBeanPostProcessor接口的類在一個循環(huán)中依次對Bean進行處理;
  3. 循環(huán)中負責(zé)依賴注入的類CommonAnnotationBeanPostProcessor發(fā)現(xiàn)屬性needInitBean@Resource修飾,需要進行注入,此時BeanFactory中沒有needInitBean這個Bean,故對其進行初始化,此時外層Bean的initValue還沒有注入進來,所以內(nèi)層Bean初始化needInitValuenull;
  4. 循環(huán)中負責(zé)依賴注入的類AutowiredAnnotationBeanPostProcessor發(fā)現(xiàn)屬性initValue@Value修飾,需要進行注入,執(zhí)行注入;
  5. 完成外層Bean的創(chuàng)建;

5. 結(jié)論

通過上述追蹤,我們可以得出出現(xiàn)我們最初問題的原因:由于@Value@Resource在注入時并非用一個類進行注入,存在先后關(guān)系

故雖然外層Bean已經(jīng)初始化一半去初始化內(nèi)層Bean,initValue仍然沒有值。

另外退一步說,如果我們使用的是@Autowire,而不是@Resource@Autowire@Value是由同一個BeanPostProceccer進行注入的

是不是@Value寫在前面,本程序就能通呢?

運行了一下是可以的,然而這并不嚴謹,因為就算是同一個BeanPostProceccer進行注入, 其屬性的注入順序是依賴反射包下的Class.getDeclaredFields方法獲得的,而此方法注釋明確寫道,返回的數(shù)組是無序的。

所以我們盡量還是避免這種寫法,將@Bean注解配置的Bean放在@Configuration注解修飾的專門用于配置的類中較為穩(wěn)妥。

ps: 如果我們將initValue使用屬性注入,而needInitBean使用@Autowire修飾setter注入,可以保證嚴謹,因為目前的實現(xiàn)都是先進行屬性注入在進行方法注入,不提倡。

到此這篇關(guān)于關(guān)于spring的@Bean注解放入引用Bean中初始化失敗分析的文章就介紹到這了,更多相關(guān)spring@Bean注解引用Bean內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 通過實例解析Python文件操作實現(xiàn)步驟

    通過實例解析Python文件操作實現(xiàn)步驟

    這篇文章主要介紹了通過實例解析Python文件操作實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • Selenium alert 彈窗處理的示例代碼

    Selenium alert 彈窗處理的示例代碼

    這篇文章主要介紹了Selenium alert 彈窗處理的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Python利用腳本實現(xiàn)自動發(fā)送電子郵件

    Python利用腳本實現(xiàn)自動發(fā)送電子郵件

    這篇文章主要為大家詳細介紹了Python如何利用腳本實現(xiàn)自動發(fā)送電子郵件功能,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-01-01
  • python中的sys模塊和os模塊

    python中的sys模塊和os模塊

    這篇文章主要介紹了python中的sys模塊和os模塊,sys模塊提供對解釋器使用或維護的一些變量的訪問,以及與解釋器強烈交互的函數(shù),os模塊提供了多數(shù)操作系統(tǒng)的功能接口函數(shù),下文更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-03-03
  • 基于Python實現(xiàn)迪杰斯特拉和弗洛伊德算法

    基于Python實現(xiàn)迪杰斯特拉和弗洛伊德算法

    這篇文章主要為大家詳細介紹了基于Python實現(xiàn)迪杰斯特拉和弗洛伊德算法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Python分支語句與循環(huán)語句應(yīng)用實例分析

    Python分支語句與循環(huán)語句應(yīng)用實例分析

    這篇文章主要介紹了Python分支語句與循環(huán)語句應(yīng)用,結(jié)合具體實例形式詳細分析了Python分支語句與循環(huán)語句各種常見應(yīng)用操作技巧與相關(guān)注意事項,需要的朋友可以參考下
    2019-05-05
  • python添加模塊搜索路徑和包的導(dǎo)入方法

    python添加模塊搜索路徑和包的導(dǎo)入方法

    今天小編就為大家分享一篇python添加模塊搜索路徑和包的導(dǎo)入方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • Python中l(wèi)ambda排序的六種方法

    Python中l(wèi)ambda排序的六種方法

    本文主要介紹了Python中使用lambda函數(shù)進行排序的六種方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • Python Django 通用視圖和錯誤視圖的使用代碼

    Python Django 通用視圖和錯誤視圖的使用代碼

    這篇文章主要介紹了Python Django 通用視圖和錯誤視圖的使用,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • python壓縮文件夾內(nèi)所有文件為zip文件的方法

    python壓縮文件夾內(nèi)所有文件為zip文件的方法

    這篇文章主要介紹了python壓縮文件夾內(nèi)所有文件為zip文件的方法,可實現(xiàn)簡單的zip文件壓縮功能,需要的朋友可以參考下
    2015-06-06

最新評論