日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

作者 | 波哥

審校 | 重樓

Spring作為當前使用最廣泛的框架之一,其重要性不言而喻。所以充分理解Spring的底層實現原理對于咱們JAVA程序員來說至關重要,那么今天筆者就詳細說說Spring框架中一個核心技術點:如何解決循環依賴問題?

Spring到底是如何解決循環依賴問題的?

什么是循環依賴問題?

Spring的循環依賴問題是指在使用Spring容器管理Bean的依賴關系時,出現多個Bean之間相互依賴,形成一個循環的依賴關系。這意味著Bean A 依賴于Bean B,同時Bean B 也依賴于Bean A,從而形成一個循環。Spring容器需要確保這些循環依賴關系被正確解決,以避免初始化Bean時出現問題。

如果你去網上搜索“Spring是如何解決循環依賴問題的”,絕大部分答案都是:Spring使用三級緩存確保循環依賴的解決,包括"singletonObjects"、"earlySingletonObjects"和"singletonFactories"等緩存,以及占位符的使用等等。這當然沒有錯,可是看到這些文章的朋友們,你們真的理解了這其中的原理嗎?還是只是會背答案呢?那么,今天筆者就來扒一扒Spring是如何解決這一問題的底層實現原理。當然要明白這個問題的底層實現原理,你得有一定的Spring源碼基礎才行哦。

現在假設我們有三個類,ClasssA、ClassB、ClassC,代碼如下:

Spring到底是如何解決循環依賴問題的?

下面,我們根據Spring關于Bean的生命周期管理過程進行分析:

假設首先實例化ClassA。我們知道在ClassA實例化完成后,需要填充屬性classB,在填充classB屬性之前,會調用addSingletonFactory方法,把一個Lambda表達式添加到了singletonFactories集合中,這個Lambda表達式的代碼如下:

Spring到底是如何解決循環依賴問題的?

Spring到底是如何解決循環依賴問題的?

Spring到底是如何解決循環依賴問題的?

在填充屬性時,需要獲取到classB的實例對象,也就是說會調用getBean("classB")來走classB這個bean實例的生命周期流程。

在獲取classB實例時,首先會調用getSingleton從singletonObjects獲取(而這個singletonObjects就是我們平常所說的單例池, 其實就是個map集合):

Spring到底是如何解決循環依賴問題的?

Spring到底是如何解決循環依賴問題的?

如果單例池中沒有才會去創建,那么此時單例池中肯定沒有ClassB的實例,所以針對classB實例也會走一遍創建實例的生命周期的流程,同樣的也會把上述Lambda表達式添加到singletonFactories集合中。

此時singletonFactories集合中就有了classA和classB的兩個表達式。

但是這里我們要特別注意classB中需要填充屬性classA,所以在填充classB實例的classA屬性時,同樣需要調用getBean("classA")方法來獲取到classA的實例,在獲取classA實例時,同樣首先會調用getSingleton從單例池中獲取:

Spring到底是如何解決循環依賴問題的?

如代碼所示,首先會根據beanName從singletonObjects獲取,也就是獲取classA,很顯然,classA還沒有放到單例池里面去,只有完全創建好的實例才會放到單例池里面去。可以看到代碼同時執行
isSingletonCurrentlyInCreation,此時這個方法返回的是true,內容如下:

Spring到底是如何解決循環依賴問題的?

那這個isSingletonCurrentlyInCreation方法是干嘛用的呢?看方法名字就知道了,就是判斷當前這個bean是否正在創建中,我們在開始創建classA的時候就已經把他的名字添加到singletonsCurrentlyInCreation這個集合中,表明正在創建classA。

很顯然滿足了if (singletonObject == null &&isSingletonCurrentlyInCreation(beanName))這個條件,于是就進入到if的方法體中。

然后從earlySingletonObjects這個集合中獲取對象,那這個earlySingletonObjects又是個啥玩意?只用singletonFactories和singletonObjects兩個緩存集合不就好了嗎?還要多此一舉使用earlySingletonObjects干啥呢?是不是感覺沒什么用?千萬別這么看,大師們考慮問題比咱們要考慮的周到,不服都不行。

我們這個案例中ClassA依賴ClassB和ClassC,ClassB依賴ClassA,ClassC也依賴ClassA,假如我們沒有這個earlySingletonObjects會出現什么情況呢?我們調用singletonFactories.get(beanName)得到前面說的classA的那個Lambda表達式,然后執行
singletonFactory.getObject()就開始執行這個Lambda表達式,在填充ClassB中的classA屬性時是不是相當于執行了這個Lambda表達式獲取了這個classA對象。

好了,到此為止classA中的classB屬性獲取到了,接下來填充classC了,上述同樣的流程,當填充classC的classA屬性時,是不是還得從singletonFactories中獲取classA的Lambda表達式,然后再執行那個Lambda表達式,于是執行了兩次,正常情況下是沒有問題的,因為兩個Lambda表達式返回的結果都是classA的實例對象,但是有一種情況下就會有問題了?老鐵們此時心中肯定充滿疑惑,神馬情況呢?

如果執行這個Lambda表達式返回的是classA的代理對象呢?如果執行了兩次,是不是就表明classB中的classA屬性和classC中的classA屬性是兩個不同的對象了?這問題可就大了,那么問題又來了,神馬情況下會返回classA的代理對象?不賣關子了,直接上答案:在classA需要AOP的情況下,是需要生成代理對象的,而這個生成AOP的騷操作就是在這個Lambda表達式中實現的,我們下面會詳細介紹。

所以這里Spring使用了earlySingletonObjects這個我們稱為二級緩存的集合來暫存下,這樣在classC填充classA屬性的時候就不用再次調用lambda表達式了,是不是完美的解決了上述的問題?剩下的幾行代碼很簡單,就不多廢話了,大家自己看看就知道了。

總結下,Spring解決循環依賴問題其實就是使用了幾個集合類,它們分別是:singletonsCurrentlyInCreation(Set)、singletonFactories(Map)、earlySingletonObjects(Map)、singletonObjects(Map),通過這幾個集合的相互配合,最終解決循環依賴問題。

作者介紹

波哥,互聯行業從業10余年,先后擔任項目總監及架構師。目前專攻技術,喜歡研究技術原理。技術全面,主攻Java,精通JVM底層機制及Spring全家桶底層框架原理,熟練掌握當前主流的中間件、服務網格等技術原理。

分享到:
標簽:Spring
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定