最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

1. Bean依賴屬性

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

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

2. 問(wèn)題背景

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

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

錯(cuò)誤代碼

編寫單元測(cè)試

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

單元測(cè)試:

單元測(cè)試

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

說(shuō)明在初始化needInitBean時(shí),外層Bean的屬性值initValue并未注入成功,

運(yùn)行結(jié)果:

測(cè)試結(jié)果

簡(jiǎn)單理下思路,因?yàn)橥鈱覤ean的類通過(guò)@Service注解進(jìn)行修飾,所以SpringBoot在啟動(dòng)時(shí)會(huì)掃描到此注解進(jìn)行Bean的初始化

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

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

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

從現(xiàn)象來(lái)看,此時(shí)initValue無(wú)值,我們有以下疑問(wèn):

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

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

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

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

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

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

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

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

注入

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

resource

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

在這里插入圖片描述

7.上面提到的遍歷邏輯,是在對(duì)外層Bean進(jìn)行依賴注入,即外層Bean的初始化過(guò)程,因?yàn)橥鈱覤ean是@Service注解修飾的,所以會(huì)在SpringBoot啟動(dòng)時(shí)掃描到進(jìn)行初始化

所以我們?cè)偻伦邲](méi)幾步就到了SpringApplication.run

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

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

5. 結(jié)論

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

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

另外退一步說(shuō),如果我們使用的是@Autowire,而不是@Resource@Autowire@Value是由同一個(gè)BeanPostProceccer進(jìn)行注入的

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

運(yùn)行了一下是可以的,然而這并不嚴(yán)謹(jǐn),因?yàn)榫退闶峭粋€(gè)BeanPostProceccer進(jìn)行注入, 其屬性的注入順序是依賴反射包下的Class.getDeclaredFields方法獲得的,而此方法注釋明確寫道,返回的數(shù)組是無(wú)序的。

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

ps: 如果我們將initValue使用屬性注入,而needInitBean使用@Autowire修飾setter注入,可以保證嚴(yán)謹(jǐn),因?yàn)槟壳暗膶?shí)現(xiàn)都是先進(jìn)行屬性注入在進(jìn)行方法注入,不提倡。

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

相關(guān)文章

  • 用Python3創(chuàng)建httpServer的簡(jiǎn)單方法

    用Python3創(chuàng)建httpServer的簡(jiǎn)單方法

    今天小編就為大家分享一篇用Python3創(chuàng)建httpServer的簡(jiǎn)單方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • Python利用PIL庫(kù)實(shí)現(xiàn)圖片轉(zhuǎn)Base64字符串的完整指南

    Python利用PIL庫(kù)實(shí)現(xiàn)圖片轉(zhuǎn)Base64字符串的完整指南

    這篇文章主要為大家詳細(xì)介紹了如何使用Python的PIL(Pillow)庫(kù)將圖像轉(zhuǎn)換為Base64編碼字符串,并提供多種實(shí)用場(chǎng)景的示例代碼,有需要的小伙伴可以了解下
    2026-01-01
  • Python argparse命令參數(shù)與config配置參數(shù)示例深入詳解

    Python argparse命令參數(shù)與config配置參數(shù)示例深入詳解

    這篇文章主要介紹了Python argparse命令參數(shù)與config配置參數(shù),argparse是Python內(nèi)置的一個(gè)用于命令項(xiàng)選項(xiàng)與參數(shù)解析的模塊,通過(guò)在程序中定義好我們需要的參數(shù),然后在程序啟動(dòng)命令行傳遞我們想要改變的參數(shù)
    2023-03-03
  • Django框架之路由用法

    Django框架之路由用法

    這篇文章介紹了Django框架之路由的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • Python的缺點(diǎn)和劣勢(shì)分析

    Python的缺點(diǎn)和劣勢(shì)分析

    在本篇文章里小編給大家整理了關(guān)于Python的缺點(diǎn)和劣勢(shì)總結(jié),有興趣的朋友們可以學(xué)習(xí)下。
    2019-11-11
  • Python使用openpyxl與pandas讀取Excel文件的對(duì)比詳解

    Python使用openpyxl與pandas讀取Excel文件的對(duì)比詳解

    在 Python 數(shù)據(jù)處理與分析場(chǎng)景中,Excel 文件作為經(jīng)典的數(shù)據(jù)存儲(chǔ)格式,其讀取與操作效率直接影響開(kāi)發(fā)流程,openpyxl具備精細(xì)化操作單元格、樣式設(shè)置、圖表編輯等底層能力;而 pandas 依托強(qiáng)大的數(shù)據(jù)結(jié)構(gòu)與矢量化運(yùn)算,本文對(duì)兩種工具進(jìn)行全方位對(duì)比
    2025-12-12
  • Python中pytest命令行實(shí)現(xiàn)環(huán)境切換

    Python中pytest命令行實(shí)現(xiàn)環(huán)境切換

    在自動(dòng)化測(cè)試過(guò)程中經(jīng)常需要在不同的環(huán)境下進(jìn)行測(cè)試驗(yàn)證,所以寫自動(dòng)化測(cè)試代碼時(shí)需要考慮不同環(huán)境切換的情況,本文主要介紹了Python中pytest命令行實(shí)現(xiàn)環(huán)境切換,感興趣的可以了解一下
    2023-07-07
  • pycharm中連接mysql數(shù)據(jù)庫(kù)的步驟詳解

    pycharm中連接mysql數(shù)據(jù)庫(kù)的步驟詳解

    在進(jìn)行Python研發(fā)的時(shí)候,pycharm是一個(gè)很好的IDE,下面這篇文章主要給大家介紹了pycharm中連接mysql數(shù)據(jù)庫(kù)的步驟,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-05-05
  • python dataframe常見(jiàn)操作方法:實(shí)現(xiàn)取行、列、切片、統(tǒng)計(jì)特征值

    python dataframe常見(jiàn)操作方法:實(shí)現(xiàn)取行、列、切片、統(tǒng)計(jì)特征值

    今天小編就為大家分享一篇python dataframe常見(jiàn)操作方法:實(shí)現(xiàn)取行、列、切片、統(tǒng)計(jì)特征值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • python中的Elasticsearch操作匯總

    python中的Elasticsearch操作匯總

    這篇文章主要介紹了python中的Elasticsearch操作匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10

最新評(píng)論

正定县| 辉南县| 元江| 内乡县| 封开县| 苗栗市| 龙井市| 钟山县| 大港区| 平安县| 房山区| 伽师县| 辛集市| 桐梓县| 长寿区| 无为县| 天津市| 济源市| 随州市| 萨迦县| 余江县| 延庆县| 平果县| 韶关市| 江阴市| 西充县| 西丰县| 自治县| 衡南县| 临颍县| 方正县| 大竹县| 乌拉特后旗| 紫云| 玉山县| 内丘县| 武平县| 盐亭县| 大化| 海南省| 台州市|