Spring源碼-Bean的初始化-循環依賴的解決

原文連接:http://www.noobyard.com/article/p-fibwqxop-nt.htmljava

http://www.noobyard.com/article/p-nntskgtu-ns.html面試

https://www.jianshu.com/p/6c359768b1dc (全面)spring

spring解決理論:java基於引用傳遞緩存

Spring循環依賴的理論依據實際上是Java基於引用傳遞,當咱們獲取到對象的引用時,對象的field或者或屬性是能夠延後設置的。
Spring單例對象的初始化其實能夠分爲三步:.net

  • createBeanInstance, 實例化,實際上就是調用對應的構造方法構造對象,此時只是調用了構造方法,spring xml中指定的property並無進行populate
  • populateBean,填充屬性,這步對spring xml中指定的property進行populate
  • initializeBean,調用spring xml中指定的init方法,或者AfterPropertiesSet方法
    會發生循環依賴的步驟集中在第一步和第二步。

三級緩存+提早曝光機制prototype

singletonObjects指單例對象的cache,singletonFactories指單例對象工廠的cache,earlySingletonObjects指提早曝光的單例對象的cache。以上三個cache構成了三級緩存,Spring就用這三級緩存巧妙的解決了循環依賴問題。代理

==================================================================xml

面試官:spring循環依賴是怎麼解決的?
回答:循環依賴就是循環引用,就是兩個或多個Bean相互之間的持有對方,好比CircleA引用CircleB,CircleB引用CircleA,則它們最終反映爲一個環。
Spring如何解決循環依賴? 
假設場景以下,A->B->A 
一、實例化A,並將未注入屬性的A暴露出去,即提早曝光給容器Wrap
二、開始爲A注入屬性,發現須要B,調用getBean(B)
三、實例化B,並注入屬性,發現須要A的時候,從單例緩存中查找,沒找到時繼而從Wrap中查找,從而完成屬性的注入
四、遞歸完畢以後回到A的實例化過程,A將B注入成功,並注入A的其餘屬性值,自此即完成了循環依賴的注入對象

spring中的循環依賴會有3種狀況:
1.構造器循環依賴
    構造器的循環依賴是不能夠解決的,spring容器將每個正在建立的bean標識符放在一個當前建立bean池中,在建立的過程一直在裏面,若是在建立的過程當中發現已經存在這個池裏面了,這時就會拋出異常表示循環依賴了。
2.setter循環依賴
   對於setter的循環依賴是經過spring容器提早暴露剛完成構造器注入,但並未完成其餘步驟(如setter注入)的bean來完成的,並且只能決定單例做用域的bean循環依賴,經過提早暴露一個單例工廠方法,從而使其餘的bean能引用到該bean.當你依賴到了該Bean而單例緩存裏面有沒有該Bean的時候就會調用該工廠方法生產Bean,
Spring是先將Bean對象實例化以後再設置對象屬性的
Spring先是用構造實例化Bean對象,此時Spring會將這個實例化結束的對象放到一個Map中,而且Spring提供了獲取這個未設置屬性的實例化對象引用的方法。blog

爲何不把Bean暴露出去,而是暴露個Factory呢?由於有些Bean是須要被代理的

3.prototype範圍的依賴
對於「prototype」做用域bean,Spring容器沒法完成依賴注入,由於「prototype」做用域的bean,Spring容器不進行緩存,所以沒法提早暴露一個建立中的Bean。

 

 

1. 什麼是循環依賴?

2. 怎麼檢測是否存在循環依賴

3. Spring怎麼解決循環依賴

4.基於構造器的循環依賴

5.基於setter屬性的循環依賴

6.結束語