1. 程式人生 > >Spring如何解決迴圈依賴

Spring如何解決迴圈依賴

一、什麼是迴圈依賴

  多個bean之間相互依賴,形成了一個閉環。 比如:A依賴於B、B依賴於c、c依賴於A

  通常來說,如果問spring容器內部如何解決迴圈依賴, 一定是指預設的單例Bean中,屬性互相引用的場景。也就是說,Spring的迴圈依賴,是Spring容器注入時候出現的問題。

    

二、Spring如何解決迴圈依賴

1,Spring中單例Bean的三級快取

  

  • 第一級快取〈也叫單例池)singletonObjects:存放已經經歷了完整生命週期的Bean物件
  • 第二級快取: earlySingletonObjects,存放早期暴露出來的Bean物件,Bean的生命週期未結束(屬性還未填充完整)
  • 第三級快取: Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工廠

2,Spring中Bean的生命週期

      

     

3,Bean初始化主要方法

  

  • getSingleton:希望從容器裡面獲得單例的bean,沒有的話
  • doCreateBean: 沒有就建立bean
  • populateBean: 建立完了以後,要填充屬性
  • addSingleton: 填充完了以後,再新增到容器進行使用

4,具體說明

  • A建立過程中需要B,於是A將自己放到三級快取裡面,去例項化B
  • B例項化的時候發現需要A,於是B先查一級快取,沒有,再查二級快取,還是沒有,再查三級快取,找到了A然後把三級快取裡面的這個A放到二級快取裡面,並刪除三級快取裡面的A
  • B順利初始化完畢,將自己放到一級快取裡面(此時B裡面的A依然是建立中狀態)然後回來接著建立A,此時B已經建立結束,直接從一級快取裡面拿到B,然後完成建立,並將A放到一級快取中。

5,圖解

  

三、為什麼使用三級快取

1,使用一級快取

  例項化A -> 將半成品的A放入singletonObjects中->填充A的屬性時發現取不到B->例項化B->從singletonObjects中取出A填充B的屬性->將成品B放入singletonObjects->將B填充到A的屬性中->將成品A放入singletonObjects。

  問題:這種基本流程是通的,但是如果在整個流程進行中,有另一個執行緒要來取A,那麼有可能拿到的只是一個屬性都為null的半成品A,這樣就會有問題。

2,使用二級快取

a)使用singletonObjects和earlySingletonObjects

  成品放在singletonObjects中,半成品放在earlySingletonObjects中

  流程可以這樣走:例項化A ->將半成品的A放入earlySingletonObjects中 ->填充A的屬性時發現取不到B->例項化B->將半成品的A放入earlySingletonObjects中->從earlySingletonObjects中取出A填充B的屬性->將成品B放入singletonObjects,並從earlySingletonObjects中刪除B->將B填充到A的屬性中->將成品A放入singletonObjects並刪除earlySingletonObjects。

  問題:這樣的流程是執行緒安全的,不過如果A上加個切面(AOP),這種做法就沒法滿足需求了,因為earlySingletonObjects中存放的都是原始物件,而我們需要注入的其實是A的代理物件。

b)使用singletonObjects和singletonFactories

  成品放在singletonObjects中,半成品通過singletonFactories來獲取

  流程是這樣的:例項化A ->建立A的物件工廠並放入singletonFactories中 ->填充A的屬性時發現取不到B->例項化B->建立B的物件工廠並放入singletonFactories中->從singletonFactories中獲取A的物件工廠並獲取A填充到B中->將成品B放入singletonObjects,並從singletonFactories中刪除B的物件工廠->將B填充到A的屬性中->將成品A放入singletonObjects並刪除A的物件工廠。

  問題:這樣的流程也適用於普通的IOC以及有併發的場景,但如果A上加個切面(AOP)的話,這種情況也無法滿足需