1. 程式人生 > >spring迴圈依賴問題排查

spring迴圈依賴問題排查

一、背景

清分服務新增一個非同步處理功能(@asyc),本地測試時發現啟動服務後有時正常有時異常。

二、程式碼再現

1、啟動類程式碼

public static void main(String[] args) throws Exception { String configLocation = "classpath:spring/*.xml"; @SuppressWarnings("resource") ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
while (true) { try { Thread.sleep(60 * 1000L); catch (Exception e) { } } }

2、服務啟動後報錯,如下:

三、問題分析

1、相同的環境,啟動服務結果不同,定位為工程程式碼引起該異常。

2、啟動類中,配置檔名採用了萬用字元,理論上配置檔案載入順序不固定。

3、從機器上的日誌可以看出,啟動成功和異常時spring/application-xxx.xml載入順序不同。

4、從錯誤日誌可以看出兩個問題點:迴圈依賴和不同的bean依賴了同一個bean的不同版本。(spring預設支援迴圈依賴)

說明:

1、bean的例項化過程:create bean →  cache bean → inject element → inject element → inject element ... ... → finish(debug模式可以跟蹤完整的bean例項化過程)

2、非迴圈依賴場景

條件:A依賴B,如果先create A

例項化過程為:create A → cache A → create B → cache B → finish B → inject B to A → finish A。(被依賴物件先finish,即B先於A例項化完成)

3、迴圈依賴場景

條件:A依賴B,B依賴A,如果先create A

例項化過程為:create A → cache A → create B → cache B → inject A to B → finish B → inject B to A → finish A。(spring允許eagerly cached instance注入到其他bean中,eagerly cached instance 指已快取但未finish的bean)

清分工程中bean的依賴比較複雜,抽象出下面的場景做說明:(下面的bean都為單例模式,非單例模式下bean不會進行cache,不支援迴圈依賴)

步驟1:A依賴B、C依賴B,B依賴C,並且B實現類的方法上存在@async註解,即B在例項化完成前會生成代理。
步驟2:A開始create,發現B未例項化,於是先cache A。
步驟3:B開始create,發現C未例項化,於是先cache B。
步驟4:C開始create,發現B已例項化,取出cache的B,注入C中,C finish。
(為什麼B未例項化完就注入到C中了?that is not fully initialized yet - a consequence of a circular reference,因為存在迴圈依賴,所以允許先注入。猜測未做是否被代理的檢測)
步驟5:生成B的代理類[email protected]
步驟6:[email protected]注入到A時,發現[email protected]原始例項B已注入到迴圈引用的C中,卻沒有使用B的最終代理類[email protected],所以拋異常。

正常情況應該為B先finish,A和C後finish,這樣可以保證B的最終代理類注入到A和C中。

四、小心陷阱

1、depends-on設定:如果A depends-on B,只會保證B先於A開始例項化(Creating instance of bean),但不保證B先於A例項完成(Finished creating instance of bean)。對於簡單的bean,例項化完成順序正常。

2、儘量保持bean的依賴關係簡單。

3、保證bean載入順序固定。

相關推薦

spring迴圈依賴問題排查

一、背景 清分服務新增一個非同步處理功能(@asyc),本地測試時發現啟動服務後有時正常有時異常。 二、程式碼再現 1、啟動類程式碼 public static void main(String[] args) throws Exception

Spring迴圈依賴問題修復

拆分的時候,把錯誤都處理完後,準備把工程起起來,發現彈簧的迴圈依賴問題。具體問題如下 Bean with name 'userManager' has been injected into other beans [daoAuthenticationProvider] in its raw ve

UnsatisfiedDependencyException之spring迴圈依賴

當A和B的service互相呼叫的時候,容易引發迴圈依賴。這時候需要不使用注入。 package com.uplus.wei; import org.springframework.beans.BeansException; import org.springframework.context

spring迴圈依賴是怎麼解決的?

spring中的迴圈依賴會有3種情況: 1.構造器迴圈依賴     構造器的迴圈依賴是不可以解決的,spring容器將每一個正在建立的bean識別符號放在一個當前建立bean池中,在建立的過程一直在裡面,如果在建立的過程中發現已經存在這個池裡面了,這時就會丟擲異常表示迴圈依賴了。 2.setter迴圈依賴  

Spring迴圈依賴問題

什麼是迴圈依賴? 迴圈依賴就是迴圈引用,指兩個或多個bean互相持有對方,比如說TestA引用TestB、TestB引用TestA,最終形成一個閉環。 注意:迴圈依賴不是指迴圈呼叫。 迴圈呼叫:指方法之間的環呼叫,迴圈呼叫是無解的,除非有終結條件,否則就是死迴圈,最終會導致記憶體溢位異常。 兩種Spring容

面試中被問Spring迴圈依賴的三種方式!!!

什麼是迴圈依賴? 迴圈依賴其實就是迴圈引用,也就是兩個或則兩個以上的 Bean 互相持有對方,最終形成閉環。比如A依賴於B,B依賴於C,C又依賴於A。如下圖: 如果在日常開發中我們用new 物件的方式發生這種迴圈依賴的話程式會在執行時一直迴圈呼叫,直至記憶體溢位報錯。下面說一下Spring是如果解決迴

Spring 迴圈依賴

在Spring注入的機制裡,人們常提到的一個問題是迴圈依賴,那麼什麼是迴圈依賴,假設有兩個bean,你中有我,我中有你,這樣一來,在容器建立bean的時候是如何處理的呢,是雞生蛋,還是蛋生雞,這是個問題。 我們先來看兩個小例子 A B類互相依賴,容器啟動log

spring 迴圈依賴注入

通過構造器注入構成的迴圈依賴 此依賴是無法解決的 只能丟擲BeanCurrentlyInCreationExcepti

spring迴圈依賴

迴圈依賴解決 constructor(此種無法解決) (看完sertter之後再來看這部分吧) 我想看過下部分setter解決迴圈

Springboot原始碼分析之Spring迴圈依賴揭祕

摘要: 若你是一個有經驗的程式設計師,那你在開發中必然碰到過這種現象:事務不生效。或許剛說到這,有的小夥伴就會大驚失色了。Spring不是解決了迴圈依賴問題嗎,它是怎麼又會發生迴圈依賴的呢?,接下來就讓我們一起揭祕Spring迴圈依賴的最本質原因。 Spring迴圈依賴流程圖 Spring迴圈依賴發生原因

Spring迴圈依賴的解決

Spring迴圈依賴的解決 什麼是迴圈依賴 迴圈依賴,是依賴關係形成了一個圓環。比如:A物件有一個屬性B,那麼這時候我們稱之為A依賴B,如果這時候B物件裡面有一個屬性A。那麼這時候A和B的依賴關係就形成了一個迴圈,這就是所謂的迴圈依賴。如果這時候IOC容器建立A物件的時候,發現B屬性,然後建立B物件,發現裡面

幫助你更好的理解Spring迴圈依賴

網上關於Spring迴圈依賴的部落格太多了,有很多都分析的很深入,寫的很用心,甚至還畫了時序圖、流程圖幫助讀者理解,我看了後,感覺自己是懂了,但是閉上眼睛,總覺得還沒有完全理解,總覺得還有一兩個坎過不去,對我這種有點笨的人來說,真的好難。當時,我就在想,如果哪一天,我理解了Spring迴圈依賴,一定要用自己的

爛大街的 Spring 迴圈依賴問題,你覺得自己會了嗎

> 文章已收錄在 GitHub [JavaKeeper](https://github.com/Jstarfish/JavaKeeper) ,N 線網際網路開發、面試必備技能兵器譜,筆記自取。 > > 微信搜「 **JavaKeeper** 」程式設計師成長充電站,網際網路技術武道場。無套路

Spring迴圈依賴的問題

  什麼是迴圈依賴?就是兩個Bean相互引用,比如用@Autowire 相互注入。   那麼Spring是如何解決這個問題的呢?在Bean還未完全例項化前(類只例項化了一部分),將bean提前暴露出來,可以被其他Bean引用。   原始碼解析:   問題1:什麼情況下需

3.1 spring5原始碼系列--迴圈依賴 之 手寫程式碼模擬spring迴圈依賴

本次部落格的目標 1. 手寫spring迴圈依賴的整個過程 2. spring怎麼解決迴圈依賴 3. 為什麼要二級快取和三級快取 4. spring有沒有解決建構函式的迴圈依賴 5. spring有沒有解決多例下的迴圈依賴. 一.  什麼是迴圈依賴? 如下圖所示:    &n

Spring Bean中迴圈依賴解決方案

在迴圈依賴是指在A中引用B,B中引用C,而C中引用A,容器建立物件時會出現死迴圈。相關解決方案如下: 1 選擇其一使其延遲載入,然後從上下文中獲取AService型別的bean即可。 現有AService 和BService,都在對方bean中注入,導致初始化時迴圈初始報錯,解決方案就是

Spring Bean注入/單例理解/迴圈依賴

理解迴圈依賴問題,首先明白spring有四種注入方式。 第一種,SET注入a類中持有b類的引用,並且a類有b的set方法。在bean中新增<property>標籤即可注入。實質上是將b例項化,然後呼叫set方法注入。 <bean id="a" class="com.qunar.poj

Spring原始碼初探-IOC(4)-Bean的初始化-迴圈依賴的解決

前言 在實際工作中,經常由於設計不佳或者各種因素,導致類之間相互依賴。這些類可能單獨使用時不會出問題,但是在使用Spring進行管理的時候可能就會丟擲BeanCurrentlyInCreationException等異常 。當丟擲這種異常時表示Spring解決不了該迴圈依賴,本文將簡要說明Spr

老師,Spring 是怎麼解決迴圈依賴的?

前言 你可能會有如下問題: 1、想看Spring原始碼,但是不知道應當如何入手去看,對整個Bean的流程沒有概念,碰到相關問題也沒有頭緒如何下手 2、看過幾遍原始碼,沒辦法徹底理解,沒什麼感覺,沒過一陣子又忘了 本文將結合實際問題,由問題引出原始碼,並在解釋時會盡量以圖表的形式讓你一步

Spring構造注入迴圈依賴(BeanCreationException/BeanCurrentlyInCreationException)及其解決辦法

1.什麼是迴圈依賴 在說什麼是迴圈依賴之前,不妨使用程式碼,先丟擲這個異常,bug重現一下。 工程目錄如下: 注意: 本文中只需要一個配置檔案:spring.xml,兩個bean:User和Role