Spring如何解決循環依賴

1、什麼是循環依賴

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

  一般來講,若是問spring容器內部如何解決循環依賴, 必定是指默認的單例Bean中,屬性互相引用的場景。也就是說,Spring的循環依賴,是Spring容器注入時候出現的問題。緩存

    

2、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,圖解

  

3、爲何使用三級緩存

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中spa

  流程能夠這樣走:實例化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的對象工廠。blog

  問題:這樣的流程也適用於普通的IOC以及有併發的場景,但若是A上加個切面(AOP)的話,這種狀況也沒法知足需求生命週期

相關文章
相關標籤/搜索