1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        記一次線上偶現(xiàn)的Spring循環(huán)依賴問題

        共 4727字,需瀏覽 10分鐘

         ·

        2022-05-11 04:18


        點擊藍色“程序員黃小斜”關(guān)注我喲

        加個“星標”,每天和你一起多進步一點點


        前情回顧


        一探

          Spring 的循環(huán)依賴,源碼詳細分析 → 真的非要三級緩存嗎?中講到了循環(huán)依賴問題

          同樣說明了?Spring?只能解決?setter?方式的循環(huán)依賴,不能解決構(gòu)造方法的循環(huán)依賴

          重點介紹了?Spring?是如何解決?setter?方式的循環(huán)依賴,感興趣的可以去看下

        二探

          既然?Spring?不能解決構(gòu)造方法的循環(huán)依賴,那么它是如何甄別構(gòu)造方法循環(huán)依賴的了?

          所以進行了二探:再探循環(huán)依賴 → Spring 是如何判定原型循環(huán)依賴和構(gòu)造方法循環(huán)依賴的?

          從源碼的角度講述了?Spring?是如何判定構(gòu)造方法循環(huán)依賴、原型循環(huán)依賴的

          感興趣的可以去看下

          大家跟源碼的時候,一定要注意版本!??!


        項目模擬


          自認為經(jīng)過了前兩探,對?Spring?循環(huán)依賴的問題已了若指掌,可面對線上突如其來的循環(huán)依賴問題,樓主竟然沒能一眼看出來?。?!

          這樓主能忍?于是樓主又跟起了?Spring?源碼,看看問題到底出在哪?

          ?SpringBoot?版本是?2.0.3.RELEASE?

          線上服務采用?k8s?部署,本地環(huán)境未采用?k8s?部署

          本地啟動從未出現(xiàn)循環(huán)依賴問題,線上環(huán)境也只是偶發(fā)的?pod?啟動失?。ㄌ崾拘畔⒅敝秆h(huán)依賴)

          問題偶發(fā),而非必現(xiàn),很是頭疼,但問題還是得解決,從提示信息著手唄

          根據(jù)錯誤提示信息,樓主模擬出了一個簡化的工程,方便我們進行問題排查

        ?

          非常簡單,完整地址:spring-other-circular-reference

          我們來看下類圖

          ?MyListener?、?MyService?、?MyManager?很常規(guī),特殊的是?MyConfig?和?MySender?

        問題復現(xiàn)

          如果按上述工程結(jié)構(gòu),本地很難復現(xiàn)問題 ,反正樓主是沒復現(xiàn)出來

          我們稍做調(diào)整,將?MySender?前置,如下

          啟動失敗,錯誤信息如下:

        org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myConfig': Unsatisfied dependency expressed through field 'myListener'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myListener': Unsatisfied dependency expressed through field 'myService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myServiceImpl': Unsatisfied dependency expressed through field 'myManager'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myManager': Unsatisfied dependency expressed through field 'mySender'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'mySender': Requested bean is currently in creation: Is there an unresolvable circular reference?

          此刻的?Is there an unresolvable circular reference??讓樓主感到了陌生


        問題分析

          我們從以下幾個方面來分析

        BeanDefinition 掃描

          目前?XML?方式的?Bean?定義越來越少,除了一些遺留的老項目,基本看不到?XML?方式的?Bean?定義了

          所以我們只關(guān)注注解方式的?Bean?定義的掃描

          文件夾的掃描順序與文件夾名字的升序一致,文件的順序與文件名的升序一致,如下所示

          有興趣的可以去跟下?ConfigurationClassParser?類中?doProcessConfigurationClass?方法;樓主做了下簡單的總結(jié)

          ?@ComponentScan?的處理早于?@Bean?

          ?BeanDefinition?掃描過程中,會按掃描順序會往?DefaultListableBeanFactory?的?beanDefinitionMap?中添加?BeanDefinition?,往?beanDefinitionNames?添加?BeanName?

          我們來跟下源碼,看是不是如上所說


          先被掃描的?BeanDefinition?的?BeanName?會被先添加到?beanDefinitionNames?

        BeanDefinition 覆蓋

          ?MyConfig?中通過?@Bean?定義了?MySender?,而?MySender?類上又用了?@Component?進行修飾

          那創(chuàng)建?MySender?實例的時候到底調(diào)用的哪個構(gòu)造方法?(有參還是無參?)

          關(guān)于 Spring Boot 中創(chuàng)建對象的疑慮 → @Bean 與 @Component 同時作用同一個類,會怎么樣?從源碼的角度分析了這個問題

          結(jié)論是:?SpringBoot 2.0.3.RELEASE?中,?@Configuration + @Bean?修飾的?BeanDefinition?會覆蓋掉?@Component?修飾的?BeanDefinition?

          也就說?MySender?類上的?@Component?其實沒用,加不加效果是一樣的,這里說的?沒用效果?僅僅指的是?MySender?的?BeanDefinition?

        Bean 實例化順序

          ?BeanDefinition?用來構(gòu)建實例,那么?MySender?上的?@Component?就有作用了,它決定了?MySender?的實例化順序

          是先于?MyConfig?、?MyListener?、?MyServiceImpl?、?MyManager?實例化的

          我們來看下?Bean?的實例化順序



          理論上來講,先被掃描的?Bean?會先被實例化;?Bean?實例化的過程中會填充屬性,可能會導致后被掃描的?Bean?提前被實例化

          如果?Bean?之間沒有依賴,那么會嚴格按照?Bean?的掃描順序?qū)嵗?/p>

        再看問題

          我們再回到前面的問題

          這種情況下,我們分析下?Is there an unresolvable circular reference??是如何產(chǎn)生的

          相較于?MyConfig?、?MyListener?、?MyManager?、?MyServiceImpl?,?MySender?是最先被掃描到的,所以它最先被實例化

          因為?MyConfig?中通過?@Bean?修飾了?MySender?的?BeanDefinition?

          會覆蓋掉?MySender?自身的無參?BeanDefinition?

          所以會通過?MySender?的有參構(gòu)造方法來創(chuàng)建?MySender?實例

          因為有參構(gòu)造方法依賴?myListener?,所以去?Spring?容器中找?MyListener?實例,沒有找到則創(chuàng)建,然后填充?MyListener?實例的屬性

          以此類推,實例的創(chuàng)建過程如下所示:

          ?Is there an unresolvable circular reference??就此產(chǎn)生

          相當于是變種的構(gòu)造方法循環(huán)依賴

        最初狀態(tài)

          我們還原?MySender?位置

          此時最先實例化的是?MyConfig?,實例化過程如下

          對象是都可以正常實例化、初始化的

          這種情況理論上來講是不會出現(xiàn)?Is there an unresolvable circular reference??

        線上問題

          一通分析下來,還是沒能找到線上?Is there an unresolvable circular reference??的原因

          很是尷尬,但是我萌生了這樣的想法:是不是在?k8s?部署過程中,?BeanDefinition?的掃描會有偶發(fā)的隨機性?


        問題修復


          雖然我們沒能找到線上問題的確切原因,但還是有辦法去根治這個問題的

          ?Spring?不能處理構(gòu)造方法循環(huán)依賴,那我們就去規(guī)避它

          刪掉?MyConfig?,?MySender?改成

        ?

          或?MySender?改成

        ?

        ?  還有?@PostConstruct?等,方式有很多,只要不產(chǎn)生構(gòu)造方法循環(huán)依賴就好


        總結(jié)


          1、?BeanDefinition?掃描順序

            如果我們?nèi)ジ创a就會發(fā)現(xiàn),以啟動類為起點,掃描啟動類同級目錄下的所有文件夾?

            按文件夾名升序順序進行掃描,會遞歸掃描每個文件夾

            文件掃描也是按文件名升序順序進行

            從線上問題來看,對這個掃描順序,樓主是持懷疑態(tài)度的:是?Spring?會偶發(fā)的隨機掃描,還是?pod?會導致偶發(fā)的隨機掃描

          2、?BeanDefinition?覆蓋

            只要我們讀了源碼,了解?Spring?對各個注解的掃描順序,就清楚它們的替換關(guān)系了

            ?BeanDefinition?覆蓋并不會影響?BeanDefinition?的掃描順序

            也就是不會改變?BeanName?在?beanDefinitionNames?中的位置,即不會影響?Bean?的示例化順序

          3、?Bean?實例化順序

            理論上來講,先被掃描到的就先被實例化,但實例化過程中的屬性填充會打亂這個順序,會將被依賴的對象提前實例化

          4、?Spring?版本

        ?    一定要結(jié)合版本來看問題

            版本不同,底層實現(xiàn)可能會不同

        轉(zhuǎn)自:青石路

        鏈接:?https://www.cnblogs.com/youzhibing/p/15835048.html?

        CTO 說了,不懂 @Autowired 和 @Resource 區(qū)別的人可以領(lǐng)盒飯了


        國家出手,開始整治互聯(lián)網(wǎng)加班了


        京東裁員殺紅眼了!說要給n+1,員工簽字后,公司又反悔了!


        —?【 THE END 】—
        公眾號[程序員黃小斜]全部博文已整理成一個目錄,請在公眾號里回復「m」獲??!

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點“在看”,關(guān)注公眾號并回復 PDF?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

        謝謝支持喲 (*^__^*)

        瀏覽 82
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            开心色国产 | 影音先锋乱伦 | 五月天我淫我色 | 日本护士多人吞精囗交视频 | 老子影院午夜伦不卡大全 | 91啪国线自产无码14c | 国产一级婬乱A片AAA毛多网站 | 日本曰又深又爽免费视频 | 精品偷拍自拍 | 女明星裸体视频 |