目錄
一、前言
二、什么是循環(huán)依賴
三、Spring Bean 的循環(huán)依賴問題
3.1 Bean 的創(chuàng)建步驟
3.2 為什么 Spring Bean 會產(chǎn)生循環(huán)依賴問題?
3.3 什么情況下循環(huán)依賴可以被處理?
四、Spring 如何解決循環(huán)依賴問題?
4.0 什么是三級緩存
4.1 簡單的循環(huán)依賴(沒有AOP)
4.1.0 創(chuàng)建Bean的前期流程源碼分析
4.1.1 創(chuàng)建A:調(diào)用doGetBean()
4.1.1.1 調(diào)用getSingleton(beanName):調(diào)用的第一個(gè)名為getSingleton的方法,嘗試從緩存中獲取Bean
4.1.1.2 調(diào)用getSingleton(beanName, singletonFactory):調(diào)用的第二個(gè)名為getSingleton的方法,去創(chuàng)建Bean
4.1.1.2.1 createBean()方法:創(chuàng)建Bean
4.1.1.2.1.1 調(diào)用addSingletonFactory方法:這個(gè)方法就是解決循環(huán)依賴問題的關(guān)鍵
4.1.2 創(chuàng)建B
4.1.2.1 調(diào)用第一個(gè)getSingleton()方法實(shí)現(xiàn)對B注入A
4.1.2.1.1 調(diào)用getEarlyBeanReference()方法:用來從singletonFactory工廠類中返回Bean
4.1.3 創(chuàng)建A和B的流程總結(jié)
4.2 結(jié)合了AOP的循環(huán)依賴
1、在給B注入的時(shí)候?yàn)槭裁匆⑷胍粋€(gè)代理對象?
2、明明在創(chuàng)建A的時(shí)候,到初始化這一步完成的時(shí)候仍然還是原始的A對象,那么如果對A有AOP增強(qiáng)的話,為什么最終在Spring容器中取出的A是代理增強(qiáng)的對象呢?Spring是在什么時(shí)候?qū)⒋韺ο蠓湃氲饺萜髦械哪兀?/p>
3、初始化的時(shí)候是對A對象本身進(jìn)行初始化(初始化之前也都是對原始A對象進(jìn)行的處理),而添加到Spring容器中以及注入到B中的都是代理對象,這樣不會有問題嗎?
4、三級緩存為什么要使用工廠而不是直接使用引用?換而言之,為什么需要這個(gè)三級緩存,直接通過二級緩存暴露一個(gè)引用不行嗎?
4.3 Spring 解決 Bean 的循環(huán)依賴的流程總結(jié)
4.4 三級緩存真的提高了效率了嗎?
五、循環(huán)依賴問題的解決方案
5.1 重新設(shè)計(jì)
5.2 使用 Setter/Field 注入
5.3 使用@Lazy注解
5.4 使用 @PostConstruct注解
5.5 實(shí)現(xiàn)ApplicationContextAware 和 InitializingBean接口
5.6 思考題:為什么在下表中的第三種情況的循環(huán)依賴能被解決,而第四種情況不能被解決呢?
第三種情況
第四種情況
六、什么樣的循環(huán)依賴無法處理?
七、面試題
7.1 Spring是如何解決的循環(huán)依賴?
7.2 為什么不直接使用一級緩存來解決循環(huán)依賴
7.3 為什么要使用三級緩存呢?直接使用一級緩存和二級緩存能解決循環(huán)依賴嗎?
一、前言
Spring中的循環(huán)依賴一直是Spring中一個(gè)很重要的話題,一方面是因?yàn)樵创a中為了解決循環(huán)依賴做了很多處理,另外一方面是因?yàn)槊嬖嚨臅r(shí)候,如果問到Spring中比較高階的問題,那么循環(huán)依賴必定逃不掉。如果你回答得好,那么這就是你的必殺技,反正,那就是面試官的必殺技,這也是取這個(gè)標(biāo)題的原因,當(dāng)然,本文的目的是為了讓你在之后的所有面試中能多一個(gè)必殺技,專門用來絕殺面試官!
本文的核心思想就是,當(dāng)面試官問:
“請講一講Spring中的循環(huán)依賴?!?/strong>的時(shí)候,我們到底該怎么回答?
主要分下面幾點(diǎn):
- 什么是循環(huán)依賴?
- 什么情況下循環(huán)依賴可以被處理?
- Spring是如何解決的循環(huán)依賴?
同時(shí)本文希望糾正幾個(gè)目前業(yè)界內(nèi)經(jīng)常出現(xiàn)的幾個(gè)關(guān)于循環(huán)依賴的錯(cuò)誤的說法:
- 只有在setter方式注入的情況下,循環(huán)依賴才能解決(錯(cuò))
- 使用第三級緩存的目的是為了提高效率(錯(cuò))
二、什么是循環(huán)依賴
通俗來講,循環(huán)依賴指的是一個(gè)實(shí)例或多個(gè)實(shí)例存在相互依賴的關(guān)系(類之間循環(huán)嵌套引用)。
舉個(gè)例子
@Component
public class AService {
? ? // A中注入了B
? ? @Autowired
? ? private BService bService;
}
?
@Component
public class BService {
? ? // B中也注入了A
? ? @Autowired
? ? private AService aService;
}
?
上述例子中?AService?依賴了?BService,BService?也依賴了?AService,這就是兩個(gè)對象之間的相互依賴。
當(dāng)然循環(huán)依賴還包括?自身依賴、多個(gè)實(shí)例之間相互依賴(A依賴于B,B依賴于C,C又依賴于A)。
// 自己依賴自己
@Component
public class A {
? ? // A中注入了A
? ? @Autowired
? ? private A a;
}
?
?
如果我們在普通Java環(huán)境下正常運(yùn)行上面的代碼調(diào)用?AService?對象并不會出現(xiàn)問題,也就是說普通對象就算出現(xiàn)循環(huán)依賴也不會存在問題,因?yàn)閷ο笾g存在依賴關(guān)系是很常見的,那么為什么被 Spring 容器管理后的對象有循環(huán)依賴的情況會出現(xiàn)問題呢?
三、Spring Bean 的循環(huán)依賴問題
被 Spring 容器管理的對象叫做 Bean,為什么 Bean 會存在循環(huán)依賴問題呢?
想要了解 Bean 的循環(huán)依賴問題,首先需要了解 Bean 是如何創(chuàng)建的(需要了解Bean的生命周期)。
3.1 Bean 的創(chuàng)建步驟
為了能更好的展示出現(xiàn)循環(huán)依賴問題的環(huán)節(jié),所以這里的 Bean 創(chuàng)建步驟做了簡化:
- 在創(chuàng)建 Bean 之前,Spring 會通過掃描獲取 BeanDefinition。
- BeanDefinition就緒后會讀取 BeanDefinition 中所對應(yīng)的 class 來加載類。
- 實(shí)例化階段:根據(jù)構(gòu)造函數(shù)來完成實(shí)例化 (未屬性注入以及初始化的對象 這里簡稱為 原始對象)
- 屬性注入階段:對 Bean 的屬性進(jìn)行依賴注入 (這里就是發(fā)生循環(huán)依賴問題的環(huán)節(jié))
- 如果 Bean 的某個(gè)方法有AOP操作,則需要根據(jù)原始對象生成代理對象。
- 最后把代理對象放入單例池(一級緩存singletonObjects)中。
兩點(diǎn)說明:
- 上面的 Bean 創(chuàng)建步驟是對于 單例(singleton) 作用域的 Bean。
- Spring 的 AOP 代理就是作為 BeanPostProcessor 實(shí)現(xiàn)的,而 BeanPostProcessor 是發(fā)生在屬性注入階段后的,所以 AOP 是在 屬性注入 后執(zhí)行的。
3.2 為什么 Spring Bean 會產(chǎn)生循環(huán)依賴問題?
通過上面的 Bean 創(chuàng)建步驟可知:實(shí)例化 Bean 后會進(jìn)行 屬性注入(依賴注入)。
如最初舉例的 AService 和 BService 的依賴關(guān)系,當(dāng) AService 創(chuàng)建時(shí),會先對 AService 進(jìn)行實(shí)例化生成一個(gè)原始對象,然后在進(jìn)行屬性注入時(shí)發(fā)現(xiàn)了需要 BService 對應(yīng)的 Bean,此時(shí)就會去為 BService 進(jìn)行創(chuàng)建,在 BService 實(shí)例化后生成一個(gè)原始對象后進(jìn)行屬性注入,此時(shí)會發(fā)現(xiàn)也需要 AService 對應(yīng)的 Bean。
這樣就會造成?AService?和?BService?的 Bean 都無法創(chuàng)建,就會產(chǎn)生?循環(huán)依賴?問題。
而這種情況只會在將Bean交給Spring管理的時(shí)候才會出現(xiàn),因?yàn)樯厦娴倪@些屬性注入操作都是Spring去做的,如果只是我們自己在Java中創(chuàng)建對象可以不去注入屬性,讓成員屬性為NULL也可以正常執(zhí)行的,這樣也就不會出現(xiàn)循環(huán)依賴的問題了。
3.3 什么情況下循環(huán)依賴可以被處理?
Spring 并不能解決所有 Bean 的循環(huán)依賴問題,接下來通過例子來看看哪些場景下的循環(huán)依賴問題是可以被解決的。
Spring中循環(huán)依賴場景有:?
(1)構(gòu)造器的循環(huán)依賴?
(2)field屬性的循環(huán)依賴。
在回答什么情況下循環(huán)依賴問題可以被解決前,首先要明確一點(diǎn),Spring解決循環(huán)依賴是有前置條件的:
- 出現(xiàn)循環(huán)依賴的Bean必須要是單例
- 依賴注入的方式不能全是構(gòu)造器注入的方式(很多博客上說,只能解決setter方法的循環(huán)依賴,這是錯(cuò)誤的)
其中第一點(diǎn)應(yīng)該很好理解,如果原型的Bean出現(xiàn)循環(huán)依賴,Spring會直接報(bào)錯(cuò),Spring 無法解決?原型作用域?出現(xiàn)的循環(huán)依賴問題。因?yàn)?Spring 不會緩存?原型?作用域的 Bean,而 Spring 依靠?緩存?來解決循環(huán)依賴問題,所以 Spring 無法解決?原型?作用域的 Bean。Spring Bean默認(rèn)都是單例的。
第二點(diǎn):不能全是構(gòu)造器注入是什么意思呢?我們還是用代碼說話:
@Component
public class A {
? ? public A(B b) {
? ? }
}
@Component
public class B {
? ? public B(A a){
? ? }
}
在上面的例子中,A中注入B的方式是通過構(gòu)造器,B中注入A的方式也是通過構(gòu)造器,這個(gè)時(shí)候循環(huán)依賴是無法被解決,如果你的項(xiàng)目中有兩個(gè)這樣相互依賴的Bean,在啟動時(shí)就會報(bào)出以下錯(cuò)誤:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
?
以上報(bào)錯(cuò)說明 Spring 無法解決?構(gòu)造器注入?出現(xiàn)的循環(huán)依賴問題。因?yàn)?構(gòu)造器注入?發(fā)生在?實(shí)例化階段,而 Spring 解決循環(huán)依賴問題依靠的?三級緩存?在?屬性注入階段,也就是說調(diào)用構(gòu)造函數(shù)時(shí)還未能放入三級緩存中,所以無法解決?構(gòu)造器注入?的循環(huán)依賴問題。
?
?
為了測試循環(huán)依賴的解決情況跟注入方式的關(guān)系,我們做如下四種情況的測試
依賴情況 |
依賴注入方式 |
循環(huán)依賴是否被解決 |
AB相互依賴(循環(huán)依賴) |
均采用setter方法注入 |
是 |
AB相互依賴(循環(huán)依賴) |
均采用構(gòu)造器注入 |
否 |
AB相互依賴(循環(huán)依賴) |
A中注入B的方式為setter方法,B中注入A的方式為構(gòu)造器 |
是 |
AB相互依賴(循環(huán)依賴) |
B中注入A的方式為setter方法,A中注入B的方式為構(gòu)造器 |
否 |
具體的測試代碼跟簡單,我就不放了。從上面的測試結(jié)果我們可以看到,不是只有在setter方法注入的情況下循環(huán)依賴才能被解決(setter注入可以利用三級緩存解決循環(huán)依賴問題),即使存在構(gòu)造器注入的場景下,循環(huán)依賴依然被可以被正常處理掉。
那么到底是為什么呢?Spring到底是怎么處理的循環(huán)依賴呢?不要急,我們接著往下看。
四、Spring 如何解決循環(huán)依賴問題?
Spring的循環(huán)依賴的理論依據(jù)其實(shí)是基于Java的引用傳遞,當(dāng)我們獲取到對象的引用時(shí),對象的field或則屬性是可以延后設(shè)置的(但是構(gòu)造器必須是在獲取引用之前)。
Spring 是靠?三級緩存?來解決循環(huán)依賴問題的,接下來了解一下?什么是三級緩存?以及?解決循環(huán)依賴問題的具體流程。
4.0 什么是三級緩存
那么Spring如何解決的循環(huán)依賴問題呢,對于單例來說,在Spring容器整個(gè)生命周期內(nèi),有且只有一個(gè)對象,所以很容易想到這個(gè)對象應(yīng)該存在Cache中,Spring為了解決單例的循環(huán)依賴問題,使用了三級緩存。
這三個(gè)緩存都是定義在DefaultSingletonBeanRegistry類中的:
/** Cache of singleton objects: bean name --> bean instance */
// 單例對象的cache:一級緩存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
?
/** Cache of early singleton objects: bean name --> bean instance */
// 提前暴光的單例對象的Cache:二級緩存
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
?
/** Cache of singleton factories: bean name --> ObjectFactory */
// 單例對象工廠的cache:三級緩存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
?
循環(huán)依賴主要的三級緩存分別是 :
- singletonObbjects:一級緩存單例池,主要存放最終形態(tài)的單例bean;我們一般獲取一個(gè)bean都是從這個(gè)緩存中獲?。恍枰f明的是并不是所有單例bean都存在這個(gè)緩存當(dāng)中,有些特殊的單例bean不存在這個(gè)緩存當(dāng)中
- earlySingletonObjects:二級緩存,主要存放的是過渡bean(原始對象/原始對象的代理對象);也就是從三級緩存當(dāng)中產(chǎn)生出來的對象;它的作用是防止在多級循環(huán)依賴的情況下重復(fù)從三級緩存當(dāng)中創(chuàng)建對象,其他對象都可以直接從二級緩存中獲取到原始對象(的代理對象);因?yàn)槿壘彺娈?dāng)中創(chuàng)建對象是需要犧牲一定得性能;有了這個(gè)緩存可以一定程度上提高效率(但是提高的效率并不明顯)。只有在調(diào)用了三級緩存中的ObjectFactory的getObject() 方法獲取原始對象(的代理對象)時(shí),才會將原始對象(的代理對象)放入二級緩存,而調(diào)用三級緩存中的ObjectFactory的getObject() 方法獲取原始對象(的代理對象)這種情況只會發(fā)生在有循環(huán)依賴的時(shí)候,所以,二級緩存在沒有循環(huán)依賴的情況下不會被使用到。二級緩存是為了提前暴露 Bean 來解決循環(huán)依賴問題,此時(shí)的 Bean 可能還沒有進(jìn)行屬性注入,只有等完成了屬性注入、初始化后的 Bean 才會上移到一級緩存(單例池)中。
- singletonFactories 三級緩存,用于存放原始對象對應(yīng)的ObjectFactory,它的作用主要是為了產(chǎn)生一個(gè)對象;每生成一個(gè)原始對象,都會將這個(gè)原始對象對應(yīng)的ObjectFactory放到三級緩存中,通過調(diào)用ObjectFactory的getObject() 方法,就能夠在需要?jiǎng)討B(tài)代理的情況下為原始對象生成代理對象并返回,否則返回原始對象,以此來處理循環(huán)依賴時(shí)還需要?jiǎng)討B(tài)代理的情況。
因?yàn)檫@個(gè)緩存當(dāng)中存到的是一個(gè)工廠;可以產(chǎn)生特定對象;程序員可以去擴(kuò)展BeanPostProcessor來定制這個(gè)工廠產(chǎn)生對象的過程;比如AOP就是擴(kuò)展了這個(gè)工廠的產(chǎn)生過程;從而完成完整的aop功能;如果沒有這個(gè)緩存那么極端情況下會出現(xiàn)循環(huán)依賴注入的bean不是一個(gè)完整的bean,或者說是一個(gè)錯(cuò)誤的bean。
為什么會存在三級緩存,主要原因就是:延遲代理對象的創(chuàng)建。設(shè)想一下,如果在實(shí)例化出一個(gè)原始對象的時(shí)候,就直接將這個(gè)原始對象的代理對象創(chuàng)建出來(如果需要?jiǎng)?chuàng)建的話),然后就放在二級緩存中,似乎感覺三級緩存就沒有存在的必要了對吧,但是請打住,這里存在的問題就是,如果真這么做了,那么每一個(gè)對象在實(shí)例化出原始對象后,就都會去創(chuàng)建代理對象,而Spring的原始設(shè)計(jì)中,代理對象的創(chuàng)建應(yīng)該是由AnnotationAwareAspectJAutoProxyCreator這個(gè)后置處理器的postProcessAfterInitialization() 來完成,也就是:在對象初始化完畢后,再去創(chuàng)建代理對象。如果真的只用兩個(gè)緩存來解決循環(huán)依賴,那么就會打破Spring對AOP的一個(gè)設(shè)計(jì)思想。
下面我們就通過分析源碼,來講解Spring是如何解決循環(huán)依賴為題的。關(guān)于循環(huán)依賴的解決方式應(yīng)該要分兩種情況來討論:
- 簡單的循環(huán)依賴(沒有AOP)
- 結(jié)合了AOP的循環(huán)依賴
4.1 簡單的循環(huán)依賴(沒有AOP)
我們先來分析一個(gè)最簡單的例子,就是上面提到的那個(gè)demo
@Component
public class A {
? ? // A中注入了B
? ? @Autowired
? ? private B b;
}
?
@Component
public class B {
? ? // B中也注入了A
? ? @Autowired
? ? private A a;
}
通過上文我們已經(jīng)知道了這種情況下的循環(huán)依賴是能夠被解決的,那么具體的流程是什么呢?我們一步步分析。
首先,我們要知道Spring在創(chuàng)建Bean的時(shí)候默認(rèn)是按照自然排序來進(jìn)行創(chuàng)建的(按照Bean名稱字典序,比如A類就要早于B類被創(chuàng)建),所以第一步Spring會去創(chuàng)建A。
與此同時(shí),我們應(yīng)該知道,Spring在創(chuàng)建Bean的過程中分為三步:
- 實(shí)例化,其實(shí)也就是調(diào)用對象的構(gòu)造方法實(shí)例化對象。對應(yīng)方法:AbstractAutowireCapableBeanFactory中的createBeanInstance方法
- 屬性注入,這一步主要是對bean的依賴屬性進(jìn)行填充。對應(yīng)方法:AbstractAutowireCapableBeanFactory的populateBean方法
- 初始化,在屬性注入之后,Spring會調(diào)用設(shè)置的init()方法來進(jìn)行初始化,對Bean進(jìn)一步進(jìn)行處理完善。對應(yīng)方法:AbstractAutowireCapableBeanFactory的initializeBean方法
這些方法在之前源碼分析的文章中都做過詳細(xì)的解讀了,如果你之前沒看過我的文章,那么你只需要知道:
- 實(shí)例化,簡單理解就是new了一個(gè)對象
- 屬性注入,為實(shí)例化中new出來的對象填充屬性
- 初始化,執(zhí)行aware接口中的方法,初始化方法,完成AOP代理
其實(shí)我們簡單的思考一下就發(fā)現(xiàn),出現(xiàn)循環(huán)依賴的問題主要在 (1)和 (2)兩個(gè)步驟上,也就是也就是(1)實(shí)例化階段會造成構(gòu)造器循環(huán)依賴和(2)屬性注入階段會造成field循環(huán)依賴。
4.1.0 創(chuàng)建Bean的前期流程源碼分析
我們先講一下創(chuàng)建Bean的前期流程,這些內(nèi)容其實(shí)在之前IOC源碼筆記中已經(jīng)講過了,這里我們就簡要復(fù)習(xí)一下。
在Spring中,如果基于XML配置bean,那么使用的容器為ClassPathXmlApplicationContext,如果是基于注解配置bean,則使用的容器為AnnotationConfigApplicationContext。以AnnotationConfigApplicationContext為例,其構(gòu)造函數(shù)如下所示:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
? ? this();
? ? register(componentClasses);
? ? // 初始化容器
? ? refresh();
}
?
在AnnotationConfigApplicationContext的構(gòu)造函數(shù)中會調(diào)用到AbstractApplicationContext的refresh() 方法,實(shí)際上無論是基于XML配置bean,還是基于注解配置bean,亦或者是Springboot中,在初始化容器時(shí)都會調(diào)用到AbstractApplicationContext的refresh() 方法中。下面看一下refresh() 方法:
public void refresh() throws BeansException, IllegalStateException {
? ? synchronized (this.startupShutdownMonitor) {
? ? ? ? StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
? ? ? ? // ......
? ? ? ? try {
? ? ? ? ? ?
? ? ? ? ? ? // ......
? ? ? ? ? ? // 初始化所有非延時(shí)加載的單例bean
? ? ? ? ? ? finishBeanFactoryInitialization(beanFactory);
? ? ? ? ? ? // ......
? ? ? ? }
? ? ? ? catch (BeansException ex) {
? ? ? ? ? ?
? ? ? ? ? ? // ......
? ? ? ? ? ? throw ex;
? ? ? ? }
? ? ? ? finally {
? ? ? ? ? ? resetCommonCaches();
? ? ? ? ? ? contextRefresh.end();
? ? ? ? }
? ? }
}
重點(diǎn)關(guān)心refresh()?方法中調(diào)用的finishBeanFactoryInitialization()?方法,該方法會初始化所有非延時(shí)加載的單例bean(也就是提前將非延遲加載的單例Bean裝配到Spring容器中),其實(shí)現(xiàn)如下:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
? ? if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
? ? ? ? ? ? beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
? ? ? ? beanFactory.setConversionService(
? ? ? ? ? ? ? ? beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
? ? }
? ?
? ? if (!beanFactory.hasEmbeddedValueResolver()) {
? ? ? ? beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
? ? }
? ? String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
? ? for (String weaverAwareName : weaverAwareNames) {
? ? ? ? getBean(weaverAwareName);
? ? }
? ? beanFactory.setTempClassLoader(null);
? ? beanFactory.freezeConfiguration();
? ? // 初始化所有非延時(shí)加載的單例bean
? ? beanFactory.preInstantiateSingletons();
}
在finishBeanFactoryInitialization()?方法中會調(diào)用到DefaultListableBeanFactory的preInstantiateSingletons()?方法,如下所示:
public void preInstantiateSingletons() throws BeansException {
? ? // ......
? ? List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
? ? // 在這個(gè)循環(huán)中通過getBean()方法初始化bean
? ? for (String beanName : beanNames) {
? ? ? ? RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
? ? ? ? if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
? ? ? ? ? ? // 判斷是否是FactoryBean
? ? ? ? ? ? if (isFactoryBean(beanName)) {
? ? ? ? ? ? ? ? // ......
? ? ? ? ? ? }
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? // 不是FactoryBean,則通過getBean()方法來初始化bean
? ? ? ? ? ? ? ? getBean(beanName);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? // ......
}
到了這里我們就了解到Spring中初始化bean,是通過調(diào)用容器的getBean()?方法來完成,在getBean()?方法中如果獲取不到bean,此時(shí)就會初始化這個(gè)bean。所以開始創(chuàng)建Bean的流程是從AbstractBeanFactory的getBean()?方法開始的,這也是我們講解循環(huán)依賴的重點(diǎn)。AbstractBeanFactory的getBean()?方法的實(shí)現(xiàn)如下:
public Object getBean(String name) throws BeansException {
? ? // 有三種情況會調(diào)用到這里
? ? // 1. 容器啟動的時(shí)候初始化A,所以調(diào)用到這里以進(jìn)行A的初始化
? ? // 2. 初始化A的時(shí)候要屬性注入B,所以調(diào)用到這里以進(jìn)行B的初始化
? ? // 3. 初始化B的時(shí)候要屬性注入A,所以調(diào)用到這里以獲取A的bean
? ? return doGetBean(name, null, null, false); // 最終會調(diào)用doGetBean()
}
基于上面的知識,我們開始解讀整個(gè)循環(huán)依賴處理的過程,整個(gè)流程應(yīng)該是以A的創(chuàng)建為起點(diǎn),前文也說了,第一步就是創(chuàng)建A嘛!
創(chuàng)建A的過程實(shí)際上就是調(diào)用getBean方法,這個(gè)方法有兩層含義:
- 創(chuàng)建一個(gè)新的Bean
- 從緩存中獲取到已經(jīng)被創(chuàng)建的對象
我們現(xiàn)在分析的是第一層含義,因?yàn)檫@個(gè)時(shí)候緩存中還沒有A嘛!
下面我們來從源碼的層面,梳理 Spring 解決 Bean 的循環(huán)依賴的整個(gè)流程。
4.1.1 創(chuàng)建A:調(diào)用doGetBean()
上面已經(jīng)分析過了,創(chuàng)建A的流程從 AbstractApplicationContext 的 refresh() 方法出發(fā),進(jìn)入 finishBeanFactoryInitialization() 方法再進(jìn)入 preInstantiateSingletons() 方法再進(jìn)入 getBean() 方法再進(jìn)入 doGetBean() 方法。
下面我們來看看?doGetBean()?方法:
AbstractBeanFactory.java
@SuppressWarnings("unchecked")
? ? protected <T> T doGetBean(
? ? ? ? ? ? String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
? ? ? ? ? ? throws BeansException {
? ? String beanName = transformedBeanName(name);
? ? Object bean;
? ? // Eagerly check singleton cache for manually registered singletons.
? ? // 1、第一個(gè)getSingleton()方法,判斷此時(shí)緩存中是否有想要獲取的Bean了,如果有了直接從緩存中獲取。如果沒有則在后面的第二個(gè)調(diào)用的getSingleton()方法中去創(chuàng)建該Bean
? ? Object sharedInstance = getSingleton(beanName);
? ? if (sharedInstance != null && args == null) {
? ? ? ? ...
? ? }
? ? else {
? ? ? ? // Fail if we're already creating this bean instance:
? ? ? ? // We're assumably within a circular reference.
?// 非單例bean是無法支持循環(huán)依賴的,所以這里判斷是否是非單例bean的循環(huán)依賴場景,如果是則拋出異常
? ? ? ? if (isPrototypeCurrentlyInCreation(beanName)) {
? ? ? ? ? ? throw new BeanCurrentlyInCreationException(beanName);
? ? ? ? }
? ? ? ? // Check if bean definition exists in this factory.
? ? ? ? BeanFactory parentBeanFactory = getParentBeanFactory();
? ? ? ? if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
? ? ? ? ? ? ...
? ? ? ? }
? ? ? ? if (!typeCheckOnly) {
? ? ? ? ? ? markBeanAsCreated(beanName);
? ? ? ? }
? ? ? ? try {
? ? ? ? ? ? RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
? ? ? ? ? ? checkMergedBeanDefinition(mbd, beanName, args);
? ? ? ? ? ? // Guarantee initialization of beans that the current bean depends on.
? ? ? ? ? ? String[] dependsOn = mbd.getDependsOn();
? ? ? ? ? ? if (dependsOn != null) {
? ? ? ? ? ? ? ? ...
? ? ? ? ? ? }
? ? ? ? ? ? // Create bean instance.
? ? ? ? ? ? if (mbd.isSingleton()) {
? ? ? ? ? ? ? ? // 2、第二個(gè)getSingleton()方法,當(dāng)從三個(gè)緩存中都沒有找到這個(gè)Bean的話,就會執(zhí)行第二個(gè)getSingleton(),在getSingleton()方法中會去調(diào)用createBean() 創(chuàng)建一個(gè) Bean 對象出來。
? ? ? ? ? ? ? ? sharedInstance = getSingleton(beanName, () -> {
? ? ? ? ? ? ? ? ? ? try {
??? // 在上面的getSingleton()方法中會調(diào)用到createBean()方法
? ? ? ? ? ? ? ? ? ? ? ? return createBean(beanName, mbd, args);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? catch (BeansException ex) {
? ? ? ? ? ? ? ? ? ? ? ? // Explicitly remove instance from singleton cache: It might have been put there
? ? ? ? ? ? ? ? ? ? ? ? // eagerly by the creation process, to allow for circular reference resolution.
? ? ? ? ? ? ? ? ? ? ? ? // Also remove any beans that received a temporary reference to the bean.
? ? ? ? ? ? ? ? ? ? ? ? destroySingleton(beanName);
? ? ? ? ? ? ? ? ? ? ? ? throw ex;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
? ? ? ? ? ? }
? ? .....
? ?
? ? return (T) bean;
}
其中的第一個(gè)?getSingleton(beanName)?是判斷?三個(gè)緩存?中是否有創(chuàng)建好的 Bean 對象,下面看它的源碼。
4.1.1.1 調(diào)用getSingleton(beanName):調(diào)用的第一個(gè)名為getSingleton的方法,嘗試從緩存中獲取Bean
首先調(diào)用getSingleton(a)方法,這個(gè)方法又會調(diào)用getSingleton(beanName, true),在上圖中我省略了這一步。
DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName) {
? ? return getSingleton(beanName, true);
}
DefaultSingletonBeanRegistry.java
@Nullable
// allowEarlyReference表示是否允許提前引用,如果為true,那么在Bean創(chuàng)建過程中,就可以通過第三級緩存獲取到該Bean,否則只能在Bean創(chuàng)建完成后才能獲取到該Bean。這個(gè)參數(shù)的作用在后面會講到。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
? ? // Quick check for existing instance without full singleton lock
? ? // 嘗試從一級緩存singletonObjects中獲取該Bean
? ? Object singletonObject = this.singletonObjects.get(beanName);
? ? // 如果一級緩存中沒有該Bean,并且該Bean正在被創(chuàng)建(只要這個(gè)beanName在SingletonCurrentlyInCreation集合中,就表明這個(gè)Bean正在被創(chuàng)建)
? ? if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
? ? ? ? // 如果一級緩存中沒有該Bean,并且該Bean正在被創(chuàng)建,那么嘗試從二級緩存earlySingletonObjects中獲取該Bean
? ? ? ? singletonObject = this.earlySingletonObjects.get(beanName);
? ? ? ? // 如果二級緩存中沒有該Bean,并且當(dāng)前允許Bean可以被提前引用(不用等Bean完全創(chuàng)建完成),那么嘗試從三級緩存singletonFactories中獲取該Bean
? ? ? ? if (singletonObject == null && allowEarlyReference) {
? ? ? ? ? ? synchronized (this.singletonObjects) {
? ? ? ? ? ? ? ? // Consistent creation of early reference within full singleton lock
? ? ? ? ? ? ? ? singletonObject = this.singletonObjects.get(beanName);
? ? ? ? ? ? ? ? if (singletonObject == null) {
? ? ? ? ? ? ? ? ? ? singletonObject = this.earlySingletonObjects.get(beanName);
? ? ? ? ? ? ? ? ? ? if (singletonObject == null) {
? ? ? ? ? ? ? ? ? ? ? ? // 從三級緩存singletonFactories中獲取該Bean的BeanFactory
? ? ? ? ? ? ? ? ? ? ? ? ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
? ? ? ? ? ? ? ? ? ? ? ? if (singletonFactory != null) {
??????????????????????????????????????????????????? // 通過三級緩存中這個(gè)Bean的工廠類來獲取這個(gè)Bean的實(shí)例化對象(此時(shí)返回的只是完成實(shí)例化的Bean,并沒有完成屬性注入和初始化,所以并不是一個(gè)完整的Bean),具體的源碼細(xì)節(jié)會在后面創(chuàng)建B類的時(shí)候講解
? ? ? ? ? ? ? ? ? ? ? ? ? ? singletonObject = singletonFactory.getObject();
??????????????????????????? // 通過singletonFactory工廠類獲取到的bean添加到二級緩存中(如果這個(gè)Bean沒有AOP增強(qiáng),那么加入到二級緩存的就是這個(gè)Bean原始的實(shí)例化對象;如果這個(gè)Bean有AOP增強(qiáng),那么工廠類返回的就是這個(gè)Bean的代理對象,就會將代理對象添加到二級緩存中)
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.earlySingletonObjects.put(beanName, singletonObject);
??????????????????????????????????????????????????? // 將三級緩存中這個(gè)Bean的工廠類移除
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.singletonFactories.remove(beanName);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return singletonObject;
}
getSingleton(beanName, true)這個(gè)方法實(shí)際上就是到緩存中嘗試去獲取Bean,整個(gè)緩存分為三級(這三個(gè)緩存其實(shí)就相當(dāng)于一個(gè)Map,key就是BeanName,value就是各自要存儲的對象):
- singletonObjects,一級緩存,存儲的是所有創(chuàng)建好了的單例Bean
- earlySingletonObjects,完成實(shí)例化,但是還未進(jìn)行屬性注入及初始化的對象
- singletonFactories,提前暴露的一個(gè)單例工廠,二級緩存中存儲的就是從這個(gè)工廠中獲取到的對象
通過上面的源碼可以看到這里分別去每一級的緩存中取數(shù)據(jù),依次從第一級開始取數(shù)據(jù),如果取得到則直接返回,取不到則往下一級查找,步驟如下:
- Spring首先從一級緩存singletonObjects中獲取。
- 如果獲取不到,并且對象正在創(chuàng)建中,就再從二級緩存earlySingletonObjects中獲取。
- 如果還是獲取不到且允許singletonFactories通過getObject()獲取,就從三級緩存singletonFactory.getObject()(三級緩存)獲取。
- 如果從三級緩存中獲取后,就將這個(gè)Bean放入earlySingletonObjects中,并將這個(gè)singletonFactory從singletonFactories中移除。其實(shí)也就是從三級緩存移動到了二級緩存。
通過源碼可以看到在第三級緩存中調(diào)用了 singletonFactories.get(beanName) 按照上文所說的會觸發(fā)執(zhí)行有 AOP 操作返回代理對象,沒有AOP操作就直接返回原始對象,并且在這里會判斷是否成功從三級緩存中取出了singletonFactory對象,如果成功獲取則通過singletonFactory獲取Bean,然后將這個(gè)半成品Bean添加到二級緩存中并刪除三級緩存中這個(gè)Bean的singletonFactory數(shù)據(jù)。
從三級緩存的分析來看,Spring解決循環(huán)依賴的訣竅就在于singletonFactories這個(gè)第三級cache。這個(gè)cache的類型是ObjectFactory,定義如下:
/**
?* 定義一個(gè)可以返回對象實(shí)例的工廠
?* @param <T>
?*/
public interface ObjectFactory<T> {
? ? T getObject() throws BeansException;
}
?
因?yàn)锳是第一次被創(chuàng)建,所以不管哪個(gè)緩存中必然都是沒有的,因此會進(jìn)入getSingleton的另外一個(gè)重載方法getSingleton(beanName, singletonFactory)。第二個(gè)?getSingleton()?其實(shí)就是去執(zhí)行傳入的singletonFactory的lambda表達(dá)式中的?createBean()?來創(chuàng)建一個(gè) Bean 對象出來。
4.1.1.2 調(diào)用getSingleton(beanName, singletonFactory):調(diào)用的第二個(gè)名為getSingleton的方法,去創(chuàng)建Bean
這個(gè)方法傳入的ObjectFactory<?>實(shí)際是一個(gè)Lambdas表達(dá)式,所以調(diào)用傳入?yún)?shù)singletonFactory的getObject()?方法,就會調(diào)用到createBean()?方法來創(chuàng)建Bean,創(chuàng)建好的Bean會加入到一級緩存中。其源碼如下:
DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
? ? Assert.notNull(beanName, "Bean name must not be null");
? ? synchronized (this.singletonObjects) {
? ? ? ? Object singletonObject = this.singletonObjects.get(beanName);
? ? ? ? if (singletonObject == null) {
? ? ? ? ? ? // ....
? ? ? ? ? ? // 省略異常處理及日志
? ? ? ? ? ? // ....
? ? ? ? ? ? // 在單例對象創(chuàng)建前先做一個(gè)標(biāo)記
? ? ? ? ? ? // 將beanName放入到singletonsCurrentlyInCreation這個(gè)集合中(這個(gè)集合相當(dāng)于一個(gè)Set集合)
? ? ? ? ? ? // 標(biāo)志著這個(gè)單例Bean正在創(chuàng)建
? ? ? ? ? ? // 如果同一個(gè)單例Bean多次被創(chuàng)建,這里會拋出異常
? ? ? ? ? ? // 加入到這個(gè)集合的BeanName就表示這個(gè)Bean正在被創(chuàng)建,這一個(gè)標(biāo)記很關(guān)鍵,后面還會用到
? ? ? ? ? ? beforeSingletonCreation(beanName);
? ? ? ? ? ? boolean newSingleton = false;
? ? ? ? ? ? boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
? ? ? ? ? ? if (recordSuppressedExceptions) {
? ? ? ? ? ? ? ? this.suppressedExceptions = new LinkedHashSet<>();
? ? ? ? ? ? }
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? // 上游傳入的lambda(也就是一個(gè)工廠類singletonFactory)在這里會被執(zhí)行,調(diào)用singletonFactory.getObject()方法會觸發(fā)執(zhí)行在lambda表達(dá)式中調(diào)用的createBean方法,去創(chuàng)建一個(gè)Bean后返回
? ? ? ? ? ? ? ? // 此時(shí)這個(gè)Bean相當(dāng)于通過createBean()方法被實(shí)例化出來了,實(shí)例化對象賦值給了singletonObject
?? // 這里得到的singletonObject就是初始化后得到的bean(或者代理bean)
? ? ? ? ? ? ? ? singletonObject = singletonFactory.getObject();
? ? ? ? ? ? ? ? newSingleton = true;
? ? ? ? ? ? }
? ? ? ? ? ? // ...
? ? ? ? ? ? // 省略catch異常處理
? ? ? ? ? ? // ...
? ? ? ? ? ? finally {
? ? ? ? ? ? ? ? if (recordSuppressedExceptions) {
? ? ? ? ? ? ? ? ? ? this.suppressedExceptions = null;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // 創(chuàng)建完成后將對應(yīng)的beanName從singletonsCurrentlyInCreation移除(表示這個(gè)Bean已經(jīng)創(chuàng)建完成了,不再是創(chuàng)建中的狀態(tài)了)
? ? ? ? ? ? ? ? afterSingletonCreation(beanName);
? ? ? ? ? ? }
? ? ? ? ? ? if (newSingleton) {
? ? ? ? ? ? ? ? // 創(chuàng)建好的Bean,會添加到一級緩存singletonObjects中,同時(shí)將這個(gè)Bean從二級緩存和三級緩存中移除。
? ? ? ? ? ? ? ? addSingleton(beanName, singletonObject);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 返回創(chuàng)建好的Bean
? ? ? ? return singletonObject;
? ? }
}
?
// 將完全創(chuàng)建好的Bean添加到一級緩存中
protected void addSingleton(String beanName, Object singletonObject) {
? ? synchronized (this.singletonObjects) {
? ? ? ? // 將完全創(chuàng)建完成的Bean添加到一級緩存中
? ? ? ? this.singletonObjects.put(beanName, singletonObject);
? ? ? ? // 將Bean從三級緩存中移除
? ? ? ? this.singletonFactories.remove(beanName);
? ? ? ? // 將Bean從二級緩存中移除
? ? ? ? this.earlySingletonObjects.remove(beanName);
? ? ? ? // 將完成創(chuàng)建的Bean添加到已注冊的單例Bean集合中
? ? ? ? this.registeredSingletons.add(beanName);
? ? }
}
?
上面getSingleton()的代碼我們主要抓住一點(diǎn),通過createBean方法返回的創(chuàng)建完成的Bean最終通過addSingleton()方法添加到了一級緩存,也就是單例池中。
那么到這里我們可以得出一個(gè)結(jié)論:一級緩存中存儲的是已經(jīng)完全創(chuàng)建好了的單例Bean。
?
4.1.1.2.1 createBean()方法:創(chuàng)建Bean
我們再展開講一下創(chuàng)建Bean的過程,創(chuàng)建Bean本質(zhì)是通過執(zhí)行?createBean()?方法中的?doCreateBean()?方法來創(chuàng)建的。源碼如下:
AbstractAutowireCapableBeanFactory.java
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
? ? ? ? throws BeanCreationException {
? ? if (logger.isTraceEnabled()) {
? ? ? ? logger.trace("Creating instance of bean '" + beanName + "'");
? ? }
// 拿到BeanDefinition(Bean定義)
? ? RootBeanDefinition mbdToUse = mbd;
?
? ? // Make sure bean class is actually resolved at this point, and
? ? // clone the bean definition in case of a dynamically resolved Class
? ? // which cannot be stored in the shared merged bean definition.
? ? Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
? ? if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
? ? ? ? mbdToUse = new RootBeanDefinition(mbd);
? ? ? ? mbdToUse.setBeanClass(resolvedClass);
? ? }
? ? // Prepare method overrides.
? ? try {
? ? ? ? mbdToUse.prepareMethodOverrides();
? ? }
? ? catch (BeanDefinitionValidationException ex) {
? ? ? ? throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
? ? ? ? ? ? ? ? beanName, "Validation of method overrides failed", ex);
? ? }
? ? try {
? ? ? ? // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
? ? ? ? Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
? ? ? ? if (bean != null) {
? ? ? ? ? ? return bean;
? ? ? ? }
? ? }
? ? catch (Throwable ex) {
? ? ? ? throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
? ? ? ? ? ? ? ? "BeanPostProcessor before instantiation of bean failed", ex);
? ? }
? ? try {
? ? ? ? // 通過調(diào)用doCreateBean()來創(chuàng)建完整的Bean
? ? ? ? Object beanInstance = doCreateBean(beanName, mbdToUse, args);
? ? ? ? if (logger.isTraceEnabled()) {
? ? ? ? ? ? logger.trace("Finished creating instance of bean '" + beanName + "'");
? ? ? ? }
? ? ? ? return beanInstance;
? ? }
? ? catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
? ? ? ? // A previously detected exception with proper bean creation context already,
? ? ? ? // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
? ? ? ? throw ex;
? ? }
? ? catch (Throwable ex) {
? ? ? ? throw new BeanCreationException(
? ? ? ? ? ? ? ? mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
? ? }
}
AbstractAutowireCapableBeanFactory.java
/**
?* 實(shí)際創(chuàng)建指定的bean的方法。 這個(gè)方法完成了 1、Bean的實(shí)例化 ? 2、Bean的屬性注入 ? 3、Bean的初始化
?* 此時(shí),預(yù)創(chuàng)建處理已經(jīng)發(fā)生,
?* 例如 檢查{@code postProcessBeforeInstantiation}回調(diào)。
?* 區(qū)分默認(rèn)bean實(shí)例化、使用工廠方法和自動裝配構(gòu)造函數(shù)。
?*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
? ? // Instantiate the bean.
? ? BeanWrapper instanceWrapper = null;
? ? .....
? ?
? ? if (instanceWrapper == null) {
? ? ? ? // 1、實(shí)例化Bean,生成的對象被稱為原始對象
? ? ? ? instanceWrapper = createBeanInstance(beanName, mbd, args);
? ? }
// 這里的bean就是A或者B的原始對象,此時(shí)沒有被屬性注入,也沒有執(zhí)行初始化邏輯
? ? Object bean = instanceWrapper.getWrappedInstance();
?
? ? .....
? ? // Eagerly cache singletons to be able to resolve circular references
? ? // even when triggered by lifecycle interfaces like BeanFactoryAware.
?????? // A是單例的,mbd.isSingleton()條件滿足
// allowCircularReferences:這個(gè)變量代表是否允許循環(huán)依賴,默認(rèn)是開啟的,條件也滿足
// isSingletonCurrentlyInCreation:正在在創(chuàng)建A,也滿足
// 所以earlySingletonExposure=true
? ? boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
? ? ? ? ? ? isSingletonCurrentlyInCreation(beanName));
? ? if (earlySingletonExposure) {
? ? ? ? if (logger.isDebugEnabled()) {
? ? ? ? ? ? logger.debug("Eagerly caching bean '" + beanName +
? ? ? ? ? ? ? ? ? ? "' to allow for resolving potential circular references");
? ? ? ? }
? ? ? ? // 將創(chuàng)建的BeanFactory添加到三級緩存中。注意此時(shí)Bean并沒有徹底創(chuàng)建完成,此時(shí)只進(jìn)行了實(shí)例化,Bean還是一個(gè)半成品
? ? ? ? addSingletonFactory(beanName, new ObjectFactory<Object>() {
?// ObjectFactory的getObejct()方法實(shí)際就會調(diào)用到getEarlyBeanReference()方法
? ? ? ? // 如果需要?jiǎng)討B(tài)代理,getEarlyBeanReference()方法會返回原始對象的代理對象
? ? ? ? // 如果不需要?jiǎng)討B(tài)代理,getEarlyBeanReference()方法會返回原始對象
? ? ? ? ? ? @Override
? ? ? ? ? ? public Object getObject() throws BeansException {
? ? ? ? ? ? ? ? return getEarlyBeanReference(beanName, mbd, bean);
? ? ? ? ? ? }
? ? ? ? });
? ? }
? ? // Initialize the bean instance.
? ? Object exposedObject = bean;
? ? try {
? ? ? ? // 2、Bean的屬性注入
? ? ? ? populateBean(beanName, mbd, instanceWrapper);
? ? ? ? if (exposedObject != null) {
? ? ? ? ? ? // 3、Bean的初始化
? ? ? ? ? ? exposedObject = initializeBean(beanName, exposedObject, mbd);
? ? ? ? }
? ? }
? ? ......
?
?// 返回創(chuàng)建完成的Bean
? ? return exposedObject;
}
注:createBeanInstance(...)該步驟會調(diào)用構(gòu)造方法,來實(shí)例化Bean
AbstractAutowireCapableBeanFactory.java
/**
?* 使用適當(dāng)?shù)膶?shí)例化策略為指定的bean創(chuàng)建一個(gè)新實(shí)例:
?* 工廠方法,構(gòu)造函數(shù)自動裝配或簡單實(shí)例化。
?* @return BeanWrapper for the new instance
?*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
? ?
? ? .......
? ? // Need to determine the constructor...(確定構(gòu)造函數(shù))
? ? Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
? ? if (ctors != null ||
? ? ? ? ? ? mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
? ? ? ? ? ? mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) ?{
? ? ? ? return autowireConstructor(beanName, mbd, ctors, args);
? ? }
? ? // No special handling: simply use no-arg constructor.(使用默認(rèn)無參構(gòu)造器,
? ? // 編程時(shí)候要求盡量保留無參構(gòu)造器,因?yàn)槟悴恢滥膫€(gè)框架在哪會用到)
? ? return instantiateBean(beanName, mbd);
}
至于其他的屬性注入populateBean()和初始化initializeBean()的源碼分析,在之前的IOC筆記中已經(jīng)講過了,這里就不再贅述了。
在populateBean()屬性注入這一步里,進(jìn)入到給A注入B的流程。
4.1.1.2.1.1 調(diào)用addSingletonFactory方法:這個(gè)方法就是解決循環(huán)依賴問題的關(guān)鍵
調(diào)用位置如下圖所示:
AbstractAutowireCapableBeanFactory..doCreateBean()
在完成Bean的實(shí)例化后,屬性注入之前Spring將Bean包裝成一個(gè)工廠添加進(jìn)了三級緩存中,對應(yīng)源碼如下:
DefaultSingletonBeanRegistry.java
/**
?* ?添加一個(gè)構(gòu)建指定單例對象的單例工廠
?* ?緊急注冊單例對象,用于解決解決循環(huán)依賴問題
?* To be called for eager registration of singletons, e.g. to be able to
?* resolve circular references.
?*/
// 這里傳入的參數(shù)也是一個(gè)lambda表達(dá)式,() -> getEarlyBeanReference(beanName, mbd, bean)
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
? ? Assert.notNull(singletonFactory, "Singleton factory must not be null");
? ? synchronized (this.singletonObjects) {
? ? ? ? // 如果在一級緩存中不存在這個(gè)Bean,那么就添加到三級緩存中
? ? ? ? if (!this.singletonObjects.containsKey(beanName)) {
? ? ? ? ? ? // 添加到三級緩存中
? ? ? ? ? ? this.singletonFactories.put(beanName, singletonFactory);
? ? ? ? ? ? // 從二級緩存中移除
? ? ? ? ? ? this.earlySingletonObjects.remove(beanName);
? ? ? ? ? ? this.registeredSingletons.add(beanName);
? ? ? ? }
? ? }
}
?
通過這個(gè)代碼的注釋我們就能知道,第三級緩存就是堅(jiān)決循環(huán)依賴問題的關(guān)鍵,而這個(gè)方法也是解決循環(huán)依賴的關(guān)鍵所在,這段代碼發(fā)生在doCreateBean(...) 方法中 createBeanInstance之后,也就是說單例對象此時(shí)已經(jīng)被實(shí)例化出來了(調(diào)用了構(gòu)造器)。這個(gè)對象已經(jīng)被生產(chǎn)出來了,雖然還不完美(還沒有進(jìn)行創(chuàng)建Bean的第二步和第三步),但是已經(jīng)能被人認(rèn)出來了(根據(jù)對象引用能定位到堆中的對象),所以Spring此時(shí)將這個(gè)對象提前曝光出來讓大家認(rèn)識,讓大家使用。
這樣做有什么好處呢?讓我們來分析一下“A的某個(gè)field或者setter依賴了B的實(shí)例對象,同時(shí)B的某個(gè)field或者setter依賴了A的實(shí)例對象”這種循環(huán)依賴的情況。A首先完成了創(chuàng)建的第一步(完成實(shí)例化),并且將自己提前曝光到singletonFactories中,此時(shí)進(jìn)行創(chuàng)建的第二步(屬性注入),發(fā)現(xiàn)自己依賴對象B,此時(shí)就嘗試去get(B),發(fā)現(xiàn)B還沒有被create,所以走create(B)的流程,B在創(chuàng)建第一步的時(shí)候發(fā)現(xiàn)自己依賴了對象A,于是嘗試get(A),嘗試一級緩存singletonObjects(肯定沒有,因?yàn)锳還沒初始化完全),嘗試二級緩存earlySingletonObjects(也沒有),嘗試三級緩存singletonFactories,由于A通過ObjectFactory將自己提前曝光了,所以B能夠通過ObjectFactory.getObject拿到A對象(雖然A還沒有初始化完全,但是總比沒有好呀),B拿到A對象后順利完成了創(chuàng)建的階段1、2、3,B完成創(chuàng)建后之后將自己放入到一級緩存singletonObjects中。此時(shí)返回A的創(chuàng)建流程中,A此時(shí)能拿到B的對象順利完成自己的創(chuàng)建階段2、3,最終A也完成了創(chuàng)建,將創(chuàng)建好的A添加到一級緩存singletonObjects中,而且更加幸運(yùn)的是,由于B拿到了A的對象引用,所以B現(xiàn)在持有的A對象也完成了創(chuàng)建。(簡單來說,就是spring創(chuàng)造了一個(gè)循環(huán)依賴的結(jié)束點(diǎn)標(biāo)識)
?
?
再回到這個(gè)方法源碼本身,這個(gè)方法只是添加了一個(gè)工廠,在創(chuàng)建A的流程中執(zhí)行到這個(gè)方法時(shí),A只是完成了實(shí)例化,還沒有完成屬性注入和初始化。上面的文字也講了B通過這個(gè)工廠(ObjectFactory)的getObject方法可以得到A對象,而這個(gè)A對象實(shí)際上就是通過getObject方法中再去調(diào)用getEarlyBeanReference這個(gè)方法創(chuàng)獲取的。既然singletonFactory.getObject()方法是在創(chuàng)建B的流程中調(diào)用的,下面我們就再進(jìn)入到創(chuàng)建B的流程中進(jìn)行講解。
4.1.2 創(chuàng)建B
當(dāng)A完成了實(shí)例化并添加進(jìn)了三級緩存后,就要通過方法populateBean()開始為A進(jìn)行屬性注入了,在注入時(shí)發(fā)現(xiàn)A依賴了B,那么這個(gè)時(shí)候Spring又會去getBean(b),然后反射調(diào)用setter方法完成屬性注入。
流程圖如下:
4.1.2.1 調(diào)用第一個(gè)getSingleton()方法實(shí)現(xiàn)對B注入A
因?yàn)锽需要注入A,所以在創(chuàng)建B的時(shí)候,又會去調(diào)用getBean(a),這個(gè)時(shí)候就又回到之前的流程了,但是不同的是,之前的getBean是為了創(chuàng)建Bean,而此時(shí)再調(diào)用getBean不是為了創(chuàng)建了,而是要從緩存中獲取,因?yàn)橹癆在實(shí)例化后已經(jīng)將其放入了三級緩存singletonFactories中,所以此時(shí)getBean(a)的流程就是這樣子了:
上面執(zhí)行的就是其實(shí)就是第一個(gè)getSingleton()方法,因?yàn)锳此時(shí)并不在一級和二級緩存中,而是在三級緩存中,所以最終會從三級緩存中獲取A,來將A注入給B。
@Nullable
// allowEarlyReference表示是否允許提前引用,如果為true,那么在Bean創(chuàng)建過程中,就可以通過getBean()方法獲取到該Bean,否則只能在Bean創(chuàng)建完成后才能獲取到該Bean
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
? ? // Quick check for existing instance without full singleton lock
? ? // 嘗試從一級緩存singletonObjects中獲取該Bean
? ? Object singletonObject = this.singletonObjects.get(beanName);
? ? // 如果一級緩存中沒有該Bean,并且該Bean正在被創(chuàng)建(只要這個(gè)beanName在SingletonCurrentlyInCreation集合中,就表明這個(gè)Bean正在被創(chuàng)建)
? ? if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
? ? ? ? // 如果一級緩存中沒有該Bean,并且該Bean正在被創(chuàng)建,那么嘗試從二級緩存earlySingletonObjects中獲取該Bean
? ? ? ? singletonObject = this.earlySingletonObjects.get(beanName);
? ? ? ? // 如果二級緩存中沒有該Bean,并且當(dāng)前允許Bean可以被提前引用(不用等Bean完全創(chuàng)建完成),那么嘗試從三級緩存singletonFactories中獲取該Bean
? ? ? ? if (singletonObject == null && allowEarlyReference) {
? ? ? ? ? ? synchronized (this.singletonObjects) {
? ? ? ? ? ? ? ? // Consistent creation of early reference within full singleton lock
? ? ? ? ? ? ? ? singletonObject = this.singletonObjects.get(beanName);
? ? ? ? ? ? ? ? if (singletonObject == null) {
? ? ? ? ? ? ? ? ? ? singletonObject = this.earlySingletonObjects.get(beanName);
? ? ? ? ? ? ? ? ? ? if (singletonObject == null) {
? ? ? ? ? ? ? ? ? ? ? ? // 從三級緩存singletonFactories中獲取該Bean的BeanFactory
? ? ? ? ? ? ? ? ? ? ? ? ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
? ? ? ? ? ? ? ? ? ? ? ? if (singletonFactory != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 調(diào)用工廠的getObject方法,其實(shí)本質(zhì)調(diào)用的就是從上游lambda表達(dá)式傳入的getEarlyBeanReference()方法
? ? ? ? ? ? ? ? ? ? ? ? ? ? singletonObject = singletonFactory.getObject();
????????????????????????????????????????????????? // 通過singletonFactory工廠類獲取到的bean添加到二級緩存中(如果這個(gè)Bean沒有AOP增強(qiáng),那么加入到二級緩存的就是這個(gè)Bean原始的實(shí)例化對象;如果這個(gè)Bean有AOP增強(qiáng),那么工廠類返回的就是這個(gè)Bean的代理對象,就會將代理對象添加到二級緩存中)
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.earlySingletonObjects.put(beanName, singletonObject);
??????????????????????????????????????????????????? // 將三級緩存中這個(gè)Bean的工廠類移除
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.singletonFactories.remove(beanName);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return singletonObject;
}
4.1.2.1.1 調(diào)用getEarlyBeanReference()方法:用來從singletonFactory工廠類中返回Bean
從上面的源碼我們可以看出,注入到B中的A是通過getEarlyBeanReference方法提前暴露出去的一個(gè)對象,還不是一個(gè)完整的Bean,那么getEarlyBeanReference到底干了啥了,我們看下它的源碼:
// 這個(gè)方法名字其實(shí)就告訴了我們它的作用了,得到一個(gè)比較早的Bean引用(還沒有完全創(chuàng)建好的Bean,僅僅只是完成了實(shí)例化的Bean,還沒有完成屬性注入和初始化)
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
? ? Object exposedObject = bean;
? ? // AOP增強(qiáng)操作
? ? if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
? ? ? ? for (BeanPostProcessor bp : getBeanPostProcessors()) {
? ? ? ? ? ? if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
? ? ? ? ? ? ? ? SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
? ? ? ? ? ? ? ? exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return exposedObject;
}
?
它實(shí)際上就是調(diào)用了后置處理器的getEarlyBeanReference,而真正實(shí)現(xiàn)了這個(gè)方法的后置處理器只有一個(gè),就是通過@EnableAspectJAutoProxy注解導(dǎo)入的AnnotationAwareAspectJAutoProxyCreator。也就是說如果在不考慮AOP的情況下,上面的代碼等價(jià)于:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
? ? Object exposedObject = bean;
? ? // 相當(dāng)于直接返回了原始Bean,并沒有進(jìn)行AOP增強(qiáng)
? ? return exposedObject;
}
也就是說這個(gè)工廠啥都沒干,直接將之前實(shí)例化階段創(chuàng)建的對象A返回了!所以說在不考慮AOP的情況下三級緩存有用嘛?講道理,真的沒什么用,我直接將這個(gè)對象放到二級緩存中不是一點(diǎn)問題都沒有嗎?所以三級緩存并沒有提高任何效率。
那么三級緩存到底有什么作用呢?不要急,我們先把整個(gè)流程走完,在下文結(jié)合AOP分析循環(huán)依賴的時(shí)候你就能體會到三級緩存的作用!
4.1.3 創(chuàng)建A和B的流程總結(jié)
到這里不知道小伙伴們會不會有疑問,B中提前注入了一個(gè)沒有經(jīng)過初始化的A類型對象不會有問題嗎?
答:不會,因?yàn)槠鋵?shí)B中注入了A的引用,在后面A徹底完成創(chuàng)建之后,A的引用并不會變,所以B最終會得到一個(gè)完整的A。
這個(gè)時(shí)候我們將整個(gè)創(chuàng)建A這個(gè)Bean的流程總結(jié)一下,如下圖:
從上圖中我們可以看到,雖然在創(chuàng)建B時(shí)會提前給B注入了一個(gè)還未初始化的A對象,但是在創(chuàng)建A的流程中一直使用的是注入到B中的A對象的引用,之后會根據(jù)這個(gè)引用對A進(jìn)行初始化,所以這是沒有問題的。
4.2 結(jié)合了AOP的循環(huán)依賴
之前我們已經(jīng)說過了,在普通的循環(huán)依賴的情況下,三級緩存沒有任何作用。三級緩存實(shí)際上跟Spring中的AOP相關(guān),我們再來看一看getEarlyBeanReference的代碼:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
? ? Object exposedObject = bean;
? ? // 如果不是合成的bean,且有實(shí)例化后置處理器,就說明這個(gè)Bean有AOP代理增強(qiáng)操作,需要提前暴露出來
? ? if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
? ? ? ? // 進(jìn)到這個(gè)if分支,說明開啟了AOP功能,且當(dāng)前Bean有實(shí)例化后置處理器
? ? ? ? // 遍歷當(dāng)前Bean的所有實(shí)例化后置處理器
? ? ? ? for (BeanPostProcessor bp : getBeanPostProcessors()) {
? ? ? ? ? ? // 如果當(dāng)前實(shí)例化后置處理器是SmartInstantiationAwareBeanPostProcessor類型的,則調(diào)用getEarlyBeanReference方法獲取代理增強(qiáng)后的Bean
? ? ? ? ? ? if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
? ? ? ? ? ? ? ? SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
? ? ? ? ? ? ? ? // 調(diào)用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法,獲取代理增強(qiáng)后的Bean。調(diào)用的AnnotationAwareAspectJAutoProxyCreator的getEarlyBeanReference方法
? ? ? ? ? ? ? ? exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return exposedObject;
}
如果在開啟AOP的情況下,那么就是調(diào)用到AnnotationAwareAspectJAutoProxyCreator(SmartInstantiationAwareBeanPostProcessor 的實(shí)現(xiàn)類)的getEarlyBeanReference方法,對應(yīng)的源碼如下:
public Object getEarlyBeanReference(Object bean, String beanName) {
? ? Object cacheKey = getCacheKey(bean.getClass(), beanName);
? ? // earlyProxyReferences 存儲的是 (beanName, bean) 鍵值對,這里的 bean 指的是原始對象(剛實(shí)例化后的對象)
? ? this.earlyProxyReferences.put(cacheKey, bean);
? ? // wrapIfNecessary() 方法用于執(zhí)行 AOP 操作,生成一個(gè)代理對象(也就是說如果有 AOP 操作最后返回的是代理對象,否則返回的還是原始對象)。
? ? return wrapIfNecessary(bean, beanName, cacheKey);
}
回到上面的例子,我們對A進(jìn)行了AOP代理的話,那么此時(shí)getEarlyBeanReference將返回一個(gè)代理后的對象,而不是實(shí)例化階段創(chuàng)建的對象,這樣就意味著B中注入的A將是一個(gè)代理對象而不是A的實(shí)例化階段創(chuàng)建后的對象。
看到這個(gè)圖你可能會產(chǎn)生下面這些疑問:
1、在給B注入的時(shí)候?yàn)槭裁匆⑷胍粋€(gè)代理對象?
答:當(dāng)我們對A進(jìn)行了AOP代理時(shí),說明我們希望從容器中獲取到的就是A代理后的對象而不是A本身,因此把A當(dāng)作依賴進(jìn)行注入時(shí)也要注入它的代理對象。
2、明明在創(chuàng)建A的時(shí)候,到初始化這一步完成的時(shí)候仍然還是原始的A對象,那么如果對A有AOP增強(qiáng)的話,為什么最終在Spring容器中取出的A是代理增強(qiáng)的對象呢?Spring是在什么時(shí)候?qū)⒋韺ο蠓湃氲饺萜髦械哪兀?/strong>
由上圖可見,創(chuàng)建A的流程中,在完成對A的初始化后,此時(shí)仍然還是原始的A對象。我們知道在A實(shí)例化之后,會將A的BeanFactory加入到第三級緩存中,這個(gè)BeanFactory可以返回AOP代理增強(qiáng)之后的A對象,但是此時(shí)在創(chuàng)建A的流程中,一直操作的是A的原始對象,并沒有通過BeanFactory獲取A的代理增強(qiáng)對象。只不過是在創(chuàng)建A所依賴的B時(shí),因?yàn)锽也同樣依賴A,而根據(jù)自然順序(按照BeanName的字典序)B在A之后創(chuàng)建,所以在對B注入A的時(shí)候三級緩存中已經(jīng)存在了A的BeanFactory,所以B注入的A是通過BeanFactory返回的A的代理增強(qiáng)后的對象。但是針對A本身的創(chuàng)建流程來說,在A初始化后,操作的仍然是A的原始對象。
那么問題來了,在我們最終通過Spring容器獲取A對象的時(shí)候一定是代理增強(qiáng)之后的A對象,那么究竟是什么時(shí)候Spring將A的代理對象加入到容器中的呢?我們還是要通過源碼來找到答案。
我們回到創(chuàng)建A的流程,定位到doCreateBean()方法,我們看當(dāng)完成對A的初始化之后,后面又再一次調(diào)用了上面講的第一個(gè)getSingleton()方法,這個(gè)方法是嘗試從緩存中獲取Bean。這里相當(dāng)于通過getSingleton(A)從緩存中獲取A。
/**
?* 實(shí)際創(chuàng)建指定的bean的方法。 這個(gè)方法完成了 1、Bean的實(shí)例化 ? 2、Bean的屬性注入 ? 3、Bean的初始化
?* 此時(shí),預(yù)創(chuàng)建處理已經(jīng)發(fā)生,
?* 例如 檢查{@code postProcessBeforeInstantiation}回調(diào)。
?* 區(qū)分默認(rèn)bean實(shí)例化、使用工廠方法和自動裝配構(gòu)造函數(shù)。
?*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
? ? // Instantiate the bean.
? ? BeanWrapper instanceWrapper = null;
? ? .....
? ?
? ? if (instanceWrapper == null) {
? ? ? ? // 1、實(shí)例化Bean
? ? ? ? instanceWrapper = createBeanInstance(beanName, mbd, args);
? ? }
? ? .....
? ? // Eagerly cache singletons to be able to resolve circular references
? ? // even when triggered by lifecycle interfaces like BeanFactoryAware.
? ? boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
? ? ? ? ? ? isSingletonCurrentlyInCreation(beanName));
? ? if (earlySingletonExposure) {
? ? ? ? if (logger.isDebugEnabled()) {
? ? ? ? ? ? logger.debug("Eagerly caching bean '" + beanName +
? ? ? ? ? ? ? ? ? ? "' to allow for resolving potential circular references");
? ? ? ? }
? ? ? ? // 將創(chuàng)建的BeanFactory添加到三級緩存中。注意此時(shí)Bean并沒有徹底創(chuàng)建完成,此時(shí)只進(jìn)行了實(shí)例化,Bean還是一個(gè)半成品
? ? ? ? addSingletonFactory(beanName, new ObjectFactory<Object>() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public Object getObject() throws BeansException {
? ? ? ? ? ? ? ? return getEarlyBeanReference(beanName, mbd, bean);
? ? ? ? ? ? }
? ? ? ? });
? ? }
? ? // Initialize the bean instance.
? ? Object exposedObject = bean;
? ? try {
? ? ? ? // 2、Bean的屬性注入
? ? ? ? populateBean(beanName, mbd, instanceWrapper);
? ? ? ? if (exposedObject != null) {
? ? ? ? ? ? // 3、Bean的初始化
? ? ? ? ? ? exposedObject = initializeBean(beanName, exposedObject, mbd);
? ? ? ? }
? ? }
? ? ......
? ? // exposedObject就是最終創(chuàng)建完成的Bean
? ? if (earlySingletonExposure) {
? ? ? ? // 在完成了Bean的初始化后,再一次調(diào)用了上面講過的第一個(gè)getSingleton()方法,區(qū)別就是這次傳入的第二個(gè)參數(shù)是false
? ? ? ? // 這次調(diào)用實(shí)現(xiàn)了從二級緩存中獲取到代理后的Bean
? ? ? ? Object earlySingletonReference = getSingleton(beanName, false);
? ? ? ? if (earlySingletonReference != null) {
? ? ? ? ? ? if (exposedObject == bean) {
? ? ? ? ? ? ? ? // 將最終完成的Bean替換成了代理對象,在上游方法中向后執(zhí)行addSingleton()方法時(shí)會將代理對象添加到一級緩存中
? ? ? ? ? ? ? ? exposedObject = earlySingletonReference;
? ? ? ? ? ? }
? ? ? ? ? ?
? ? ? ? ? ? ...
? ? ? ? }
? ? }
? ? ......
? ? // 返回最終創(chuàng)建完成的Bean
? ? return exposedObject;
}
由源碼可知Spring又調(diào)用了一次getSingleton方法,但這一次傳入的參數(shù)又不一樣了,第二個(gè)參數(shù)傳入的是false,false可以理解為禁用第三級緩存,前面圖中已經(jīng)提到過了,在為B中注入A后,就將A的BeanFactory返回的代理對象加到了二級緩存中,并就將A的BeanFactory從三級緩存中的移除。此時(shí)A的BeanFactory已經(jīng)不在三級緩存中了,并且在本次調(diào)用getSingleton方法是傳入的參數(shù)已經(jīng)保證了禁用第三級緩存了,所以這里的這個(gè)getSingleton方法做的實(shí)際就是從二級緩存中獲取到這個(gè)代理后的A對象。exposedObject == bean可以認(rèn)為是一定成立的,除非你非要在初始化階段的后置處理器中替換掉正常流程中的Bean,例如增加一個(gè)后置處理器:
@Component
public class MyPostProcessor implements BeanPostProcessor {
? ? @Override
? ? public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
? ? ? ? if (beanName.equals("a")) {
? ? ? ? ? ? // 換成別的Bean
? ? ? ? ? ? return new A();
? ? ? ? }
? ? ? ? return bean;
? ? }
}
不過,請不要做這種騷操作,徒增煩惱!
至此,在A的創(chuàng)建流程中,就已經(jīng)將原始Bean換成了經(jīng)過AOP增強(qiáng)的Bean了。在前面講過的創(chuàng)建A的流程中addSingleton()方法中,也就將這個(gè)徹底創(chuàng)建完成的代理增強(qiáng)的Bean加入到了一級緩存中,并且在最后返回給了Spring容器。
3、初始化的時(shí)候是對A對象本身進(jìn)行初始化(初始化之前也都是對原始A對象進(jìn)行的處理),而添加到Spring容器中以及注入到B中的都是代理對象,這樣不會有問題嗎?
答:不會,這是因?yàn)椴还苁莄glib代理還是jdk動態(tài)代理生成的代理類,內(nèi)部都持有一個(gè)目標(biāo)類的引用,當(dāng)調(diào)用代理對象的方法時(shí),實(shí)際會去調(diào)用目標(biāo)對象的方法,A原始類完成初始化相當(dāng)于代理對象自身也完成了初始化。
4、三級緩存為什么要使用工廠而不是直接使用引用?換而言之,為什么需要這個(gè)三級緩存,直接通過二級緩存暴露一個(gè)引用不行嗎?
答:這個(gè)工廠的目的在于延遲對實(shí)例化階段生成的對象的代理,只有真正發(fā)生循環(huán)依賴的時(shí)候,才去提前生成代理對象,否則只會創(chuàng)建一個(gè)工廠并將其放入到三級緩存中,但是不會去通過這個(gè)工廠去真正創(chuàng)建對象。
我們思考一種簡單的情況,就以單獨(dú)創(chuàng)建A為例,假設(shè)AB之間現(xiàn)在沒有依賴關(guān)系,但是A被代理了,這個(gè)時(shí)候創(chuàng)建A會進(jìn)入到doCreateBean()方法中,當(dāng)A完成實(shí)例化后還是會繼續(xù)向下執(zhí)行這段代碼:
AbstractAutowireCapableBeanFactory..doCreateBean()
......
// A是單例的,mbd.isSingleton()條件滿足
// allowCircularReferences:這個(gè)變量代表是否允許循環(huán)依賴,默認(rèn)是開啟的,條件也滿足
// isSingletonCurrentlyInCreation:正在在創(chuàng)建A,也滿足
// 所以earlySingletonExposure=true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? isSingletonCurrentlyInCreation(beanName));
// 還是會進(jìn)入到這段代碼中
if (earlySingletonExposure) {
? ? // 還是會通過三級緩存提前暴露一個(gè)工廠對象
? ? addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
......
通過源碼我們就能發(fā)現(xiàn),即使沒有循環(huán)依賴,也會將其添加到三級緩存中,而且是不得不添加到三級緩存中,因?yàn)榈侥壳盀橹惯€沒有到對A進(jìn)行屬性注入的階段,Spring也不能確定這個(gè)Bean有沒有跟別的Bean出現(xiàn)循環(huán)依賴。
假設(shè)我們在這里直接使用二級緩存的話,那么意味著所有的Bean在這一步都要完成AOP代理。這樣做有必要嗎?
不僅沒有必要,而且違背了Spring在結(jié)合AOP和Bean的生命周期的設(shè)計(jì)原則!Spring結(jié)合AOP和Bean的生命周期本身就是通過AnnotationAwareAspectJAutoProxyCreator這個(gè)后置處理器來完成的(上面講過的返回AOP代理的getEarlyBeanReference()方法就是這個(gè)后置處理器提供的),在這個(gè)后置處理器的postProcessAfterInitialization方法會在初始化后被調(diào)用,完成對Bean的AOP代理。如果出現(xiàn)了循環(huán)依賴,那沒有辦法,只有給Bean先創(chuàng)建代理;但是沒有出現(xiàn)循環(huán)依賴的情況下,Spring的源碼設(shè)計(jì)就是在Bean完成初始化之后,調(diào)用執(zhí)行postProcessAfterInitialization方法完成AOP代理,也就是在生命周期的最后一步完成代理而不是在實(shí)例化后就立馬完成代理。所以如果只使用二級緩存的話,那么完成代理的步驟就會被提到實(shí)例化之后了,和Spring的底層源碼流程不符。在下一節(jié)我們會展示使用三級緩存和使用二級緩存的Bean創(chuàng)建流程的差異,就能很直觀地看出來了。
4.3 Spring 解決 Bean 的循環(huán)依賴的流程總結(jié)
還是以?AService?和?BService?的循環(huán)依賴為例,我們來總結(jié)一下 Spring 是如何解決 Bean 的循環(huán)依賴問題。
梳理整個(gè)流程:
- 首先會獲取 AService 對應(yīng)的 Bean 對象。
- 先是調(diào)用 doGetBean() 中的第一個(gè) getSingleton(beanName) 判斷是否有該 Bean 的實(shí)例,有就直接返回了。(顯然這里沒有)
- 然后調(diào)用 doGetBean() 中的第二個(gè) getSingleton() 方法來執(zhí)行 doCreateBean() 方法。
- 先進(jìn)行實(shí)例化操作(也就是利用構(gòu)造函數(shù)實(shí)例化),此時(shí)實(shí)例化后生成的是原始對象。
- 將原始對象通過 lambda表達(dá)式 進(jìn)行封裝成 ObjectFactory 對象,通過 addSingletonFactory 加入三級緩存中。
- 然后再進(jìn)行屬性注入,此時(shí)發(fā)現(xiàn)需要注入 BService 的 Bean,會通過 doGetBean() 去獲取 BService 對應(yīng)的 Bean。
- 同樣調(diào)用 doGetBean() 中的第一個(gè) getSingleton(beanName) 判斷是否有該 Bean 的實(shí)例,顯然這里也是不會有 BService 的 Bean 的。
- 然后只能調(diào)用 doGetBean() 中的第二個(gè) getSingleton() 方法來執(zhí)行 doCreateBean() 方法來創(chuàng)建一個(gè) BService 的 Bean。
- 同樣地先進(jìn)行實(shí)例化操作,生成原始對象后封裝成 ObjectFactory 對象放入三級緩存中。
- 然后進(jìn)行屬性注入,此時(shí)發(fā)現(xiàn)需要注入 AService 的 Bean,此時(shí)調(diào)用調(diào)用 doGetBean() 中的第一個(gè) getSingleton(beanName) 查找是否有 AService 的 Bean。此時(shí)會觸發(fā)三級緩存,也就是調(diào)用 singletonFactories.get(beanName)。
- 因?yàn)槿壘彺嬷杏?AService 的原始對象封裝的 ObjectFactory 對象,所以可以獲取到的代理對象或原始對象,并且上移到二級緩存中,提前暴露給 BService 調(diào)用。
- 所以 BService 可以完成屬性注入,然后進(jìn)行初始化后,將 Bean 放入一級緩存,這樣 AService 也可以完成創(chuàng)建。
以上就是 Spring 解決 Bean 的循環(huán)依賴問題的整個(gè)流程了。
帶著調(diào)用方法的流程圖:
4.4 三級緩存真的提高了效率了嗎?
現(xiàn)在我們已經(jīng)知道了第三級緩存的真正作用,但是這個(gè)答案可能還無法說服你,所以我們再最后總結(jié)分析一波,三級緩存真的提高了效率了嗎?分為兩點(diǎn)討論:
- 沒有進(jìn)行AOP的Bean間的循環(huán)依賴
從上文分析可以看出,這種情況下第三級緩存根本沒用!所以不會存在什么提高了效率的說法
- 進(jìn)行了AOP的Bean間的循環(huán)依賴
就以我們上的A、B為例,其中A被AOP代理,我們先分析下使用了第三級緩存的情況下,A、B的創(chuàng)建流程
假設(shè)不使用第三級緩存,直接將代理對象放到二級緩存中
上面兩個(gè)流程的唯一區(qū)別在于為A對象創(chuàng)建代理的時(shí)機(jī)不同,在使用了三級緩存的情況下為A創(chuàng)建代理的時(shí)機(jī)是在B中需要注入A的時(shí)候,而不使用三級緩存的話在A實(shí)例化后就需要馬上為A創(chuàng)建代理然后放入到二級緩存中去。對于整個(gè)A、B的創(chuàng)建過程而言,消耗的時(shí)間是一樣的
綜上,不管是哪種情況,三級緩存提高了效率這種說法都是錯(cuò)誤的!
五、循環(huán)依賴問題的解決方案
解決循環(huán)依賴問題有一些比較常用的解決方案,下面來依次講解。
5.1 重新設(shè)計(jì)
當(dāng)你面臨一個(gè)循環(huán)依賴問題時(shí),有可能是你對JavaBean的設(shè)計(jì)有問題,沒有將各自的依賴做到很好的分離。你應(yīng)該盡量正確地重新設(shè)計(jì)JavaBean,以保證它們的層次是精心設(shè)計(jì)的,避免沒有必要的循環(huán)依賴。
如果不能重新設(shè)計(jì)組件(可能有很多的原因:遺留代碼,已經(jīng)被測試并不能修改代碼,沒有足夠的時(shí)間或資源來完全重新設(shè)計(jì)......),但有一些變通方法可以解決這個(gè)問題。
5.2 使用 Setter/Field 注入
最流行的解決循環(huán)依賴的方法,就是Spring文檔中建議的,設(shè)計(jì)Bean的時(shí)候都使用setter注入。簡單地說,你對你須要注入的bean是使用setter注入(或字段注入),而不是構(gòu)造函數(shù)注入。通過這種注入方式產(chǎn)生循環(huán)依賴的Bean,Spring框架自身就能解決,也就是上面我們用了這么大篇幅講解的內(nèi)容。
5.3 使用@Lazy注解
如果產(chǎn)生循環(huán)依賴的Bean,都是通過構(gòu)造方法來注入彼此的,那么這種情況是沒有辦法通過Spring框架自身來解決的。
解決這種情況的一個(gè)簡單方法就是對一個(gè)Bean使用延時(shí)加載。也就是說:通過在構(gòu)造器參數(shù)中標(biāo)識@Lazy注解,Spring 生成并返回了一個(gè)代理對象,因此給CircularDependencyA注入的CircularDependencyB并非真實(shí)對象而是其代理。
舉一個(gè)具體的例子:
@Component
public class CircularDependencyA {
?
? ? private CircularDependencyB circB;
?
? ? @Autowired
? ? public CircularDependencyA(CircularDependencyB circB) {
? ? ? ? this.circB = circB;
? ? }
}
?
@Component
public class CircularDependencyB {
?
? ? private CircularDependencyA circA;
?
? ? @Autowired
? ? public CircularDependencyB(CircularDependencyA circA) {
? ? ? ? this.circA = circA;
? ? }
}
我們對CircularDependencyA 進(jìn)行修改,結(jié)果如下:
@Component
public class CircularDependencyA {
?
? ? private CircularDependencyB circB;
?
? ? @Autowired
? ? // 對傳入的B實(shí)行延遲加載,即可解決循環(huán)依賴的問題
? ? public CircularDependencyA(@Lazy CircularDependencyB circB) {
? ? ? ? this.circB = circB;
? ? }
}
如果你現(xiàn)在運(yùn)行測試,你會發(fā)現(xiàn)之前的循環(huán)依賴錯(cuò)誤不存在了。
結(jié)論:
Spring構(gòu)造器注入循環(huán)依賴的解決方案是@Lazy,其基本思路是:對于強(qiáng)依賴的對象,一開始并不注入對象本身,而是注入其代理對象,以便順利完成實(shí)例的構(gòu)造,形成一個(gè)完整的對象,這樣與其它應(yīng)用層對象就不會形成互相依賴的關(guān)系;當(dāng)需要調(diào)用真實(shí)對象的方法時(shí),通過TargetSource去拿到真實(shí)的對象(DefaultListableBeanFactory#doResolveDependency),然后通過反射完成調(diào)用
5.4 使用 @PostConstruct注解
打破循環(huán)的另一種方式是,在要注入的屬性(該屬性是一個(gè)bean)上使用 @Autowired,并使用@PostConstruct 標(biāo)注在另一個(gè)方法,且該方法里設(shè)置對其他的依賴。
我們的Bean將修改成下面的代碼:
@Component
public class CircularDependencyA {
?
? ? @Autowired
? ? private CircularDependencyB circB;
? ?
? ? // A的構(gòu)造方法完成后執(zhí)行
? ? @PostConstruct
? ? public void init() {
? ? ? ? // 通過setter給B注入A
? ? ? ? circB.setCircA(this);
? ? }
?
? ? public CircularDependencyB getCircB() {
? ? ? ? return circB;
? ? }
}
?
@Component
public class CircularDependencyB {
?
? ? private CircularDependencyA circA;
? ? ?
? ? private String message = "Hi!";
?
? ? public void setCircA(CircularDependencyA circA) {
? ? ? ? this.circA = circA;
? ? }
? ? ?
? ? public String getMessage() {
? ? ? ? return message;
? ? }
}
現(xiàn)在我們運(yùn)行我們修改后的代碼,發(fā)現(xiàn)并沒有拋出異常,并且依賴正確注入進(jìn)來。
5.5 實(shí)現(xiàn)ApplicationContextAware 和 InitializingBean接口
如果一個(gè)Bean實(shí)現(xiàn)了ApplicationContextAware,該Bean可以訪問Spring上下文,并可以從那里獲取到其他的bean。實(shí)現(xiàn)InitializingBean接口,表明這個(gè)bean在所有的屬性設(shè)置完后做一些后置處理操作(調(diào)用的順序?yàn)閕nit-method后調(diào)用)。在這種情況下,我們需要手動設(shè)置依賴。
@Component
public class CircularDependencyA implements ApplicationContextAware, InitializingBean {
?
? ? private CircularDependencyB circB;
?
? ? private ApplicationContext context;
?
? ? public CircularDependencyB getCircB() {
? ? ? ? return circB;
? ? }
?
? ? @Override
? ? public void afterPropertiesSet() throws Exception {
? ? ? ? circB = context.getBean(CircularDependencyB.class);
? ? }
?
? ? @Override
? ? public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
? ? ? ? context = ctx;
? ? }
}
public class CircularDependencyB {
?
? ? private CircularDependencyA circA;
?
? ? private String message = "Hi!";
?
? ? @Autowired
? ? public void setCircA(CircularDependencyA circA) {
? ? ? ? this.circA = circA;
? ? }
?
? ? public String getMessage() {
? ? ? ? return message;
? ? }
}
同樣,發(fā)現(xiàn)沒有異常拋出,程序結(jié)果是我們所期望的那樣。
5.6 思考題:為什么在下表中的第三種情況的循環(huán)依賴能被解決,而第四種情況不能被解決呢?
提示:Spring在創(chuàng)建Bean時(shí)默認(rèn)會根據(jù)自然排序進(jìn)行創(chuàng)建,所以A會先于B進(jìn)行創(chuàng)建
依賴情況 |
依賴注入方式 |
循環(huán)依賴是否被解決 |
AB相互依賴(循環(huán)依賴) |
均采用setter方法注入 |
是 |
AB相互依賴(循環(huán)依賴) |
均采用構(gòu)造器注入 |
否 |
AB相互依賴(循環(huán)依賴) |
A中注入B的方式為setter方法,B中注入A的方式為構(gòu)造器 |
是 |
AB相互依賴(循環(huán)依賴) |
B中注入A的方式為setter方法,A中注入B的方式為構(gòu)造器 |
否 |
其實(shí)這個(gè)原因很好理解。通過上面對Spring解決循環(huán)依賴問題原理的講解,我們已經(jīng)對它底層代碼有了一定了解。我們再拿過來這個(gè)流程圖,對著圖來進(jìn)行講解:
第三種情況
第三種情況的循環(huán)依賴是可以被Spring自身解決的。我們按照上面的流程圖梳理一下就能明白了。
Spring根據(jù)beanName字典序來進(jìn)行創(chuàng)建,所以先創(chuàng)建A。A是通過setter方法注入B的,所以A可以正常執(zhí)行完createBeanInstance()方法完成實(shí)例化,在執(zhí)行完實(shí)例化方法之后,就會執(zhí)行addSingletonFactory()方法來講A的beanFactory加入到第三級緩存中,在后面對A進(jìn)行屬性注入時(shí),發(fā)現(xiàn)它依賴了B,就進(jìn)入到了創(chuàng)建B的流程,而B也依賴了A,是通過構(gòu)造方法注入的A,所以B在執(zhí)行到實(shí)例化階段時(shí)候,在構(gòu)造方法中就開始嘗試注入A了,會通過前面已經(jīng)加入到第三級緩存的beanFactory來獲取到A,注入給B,所以B就順利注入了A,完成了整個(gè)創(chuàng)建過程。然后A也就能順利注入B,最終完成了創(chuàng)建過程。至此,A和B都完成了創(chuàng)建。
第四種情況
這個(gè)情況的循環(huán)依賴是沒辦法通過Spring自身解決的。
依然是先創(chuàng)建A,但是A是通過構(gòu)造方法注入的B,也就是說A在注入B的時(shí)候,仍然還在實(shí)例化階段,實(shí)例化方法還沒有執(zhí)行完。通過上面我們知道,將A的beanFactory加入到三級緩存的addSingletonFactory()方法是在完成實(shí)例化方法createBeanInstance()之后執(zhí)行的,但是此時(shí)仍然在實(shí)例化的過程中,三級緩存中還沒有A的beanFactory,這個(gè)時(shí)候就去注入B,在進(jìn)入到創(chuàng)建B的流程中時(shí),又會對B來注入A,但此時(shí)三級緩存中獲取不到對應(yīng)的beanFactory,也就無法得到A,無法完成對B的創(chuàng)建,后續(xù)的流程也就無法推進(jìn)下去,這樣就直接報(bào)錯(cuò)循環(huán)依賴問題了。
六、什么樣的循環(huán)依賴無法處理?
1、因?yàn)榧尤雜ingletonFactories三級緩存的前提是執(zhí)行了構(gòu)造器來創(chuàng)建半成品的對象,所以構(gòu)造器的循環(huán)依賴沒法解決(指的是沒辦法通過Spring自身解決,但是可以通過程序員自己使用@Lazy注解來解決)。因此Spring不能解決“A的構(gòu)造方法中依賴了B的實(shí)例對象,同時(shí)B的構(gòu)造方法中依賴了A的實(shí)例對象”這類問題了!
2、spring不支持原型(prototype)bean屬性注入循環(huán)依賴,不同于構(gòu)造器注入循環(huán)依賴會在創(chuàng)建spring容器context時(shí)報(bào)錯(cuò),它會在用戶執(zhí)行代碼如context.getBean()時(shí)拋出異常。因?yàn)閷τ谠蚥ean,spring容器會在每一次使用它的時(shí)候創(chuàng)建一個(gè)全新的Bean。
因?yàn)閟pring容器不緩存prototype類型的bean,使得無法提前暴露出一個(gè)創(chuàng)建中的bean。spring容器在獲取prototype類型的bean時(shí),如果因?yàn)檠h(huán)依賴的存在,檢測到當(dāng)前線程已經(jīng)正在處理該bean時(shí),就會拋出異常。核心代碼:
public abstract class AbstractBeanFactory{
? ? /** Names of beans that are currently in creation */
? ? private final ThreadLocal<Object> prototypesCurrentlyInCreation =
? ? ? ? ? ? new NamedThreadLocal<>("Prototype beans currently in creation");
? ? ? ? ? ?
? ? protected boolean isPrototypeCurrentlyInCreation(String beanName) {
? ? ? ? Object curVal = this.prototypesCurrentlyInCreation.get();
? ? ? ? // 如果beanName已經(jīng)存在于正在處理中的prototype類型的bean集中,后面會拋出異常
? ? ? ? return (curVal != null &&
? ? ? ? ? ? ? ? (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
? ? }
}
七、面試題
7.1 Spring是如何解決的循環(huán)依賴?
答:Spring通過三級緩存解決了循環(huán)依賴,其中一級緩存為單例池(singletonObjects),二級緩存為早期曝光對象earlySingletonObjects,三級緩存為早期曝光對象工廠(singletonFactories)。當(dāng)A、B兩個(gè)類發(fā)生循環(huán)引用時(shí),在A完成實(shí)例化后,就使用實(shí)例化后的對象去創(chuàng)建一個(gè)對象工廠,并添加到三級緩存中,如果A被AOP代理,那么通過這個(gè)工廠獲取到的就是A代理后的對象,如果A沒有被AOP代理,那么通過這個(gè)工廠獲取到的就是A實(shí)例化的對象。當(dāng)A進(jìn)行屬性注入時(shí),會去創(chuàng)建B,同時(shí)B又依賴了A,所以創(chuàng)建B的同時(shí)又會去調(diào)用getBean(a)來獲取需要的依賴,此時(shí)的getBean(a)會從緩存中獲取,第一步,先獲取到三級緩存中的工廠;第二步,調(diào)用對象工工廠的getObject方法來獲取到對應(yīng)的對象,得到這個(gè)對象后將其注入到B中。緊接著B會走完它的生命周期流程,包括初始化、后置處理器等。當(dāng)B創(chuàng)建完后,會將B再注入到A中,此時(shí)A再完成它的整個(gè)生命周期。至此,循環(huán)依賴結(jié)束!
簡單點(diǎn)說,Spring解決循環(huán)依賴的思路就是:當(dāng)A的bean需要B的bean的時(shí)候,提前將A的bean放在緩存中(實(shí)際是將A的ObjectFactory放到三級緩存),然后再去創(chuàng)建B的bean,但是B的bean也需要A的bean,那么這個(gè)時(shí)候就去緩存中拿A的bean,B的bean創(chuàng)建完畢后,再回來繼續(xù)創(chuàng)建A的bean,最終完成循環(huán)依賴的解決。Spring 利用?三級緩存?巧妙地將出現(xiàn)?循環(huán)依賴?時(shí)的?AOP 操作?提前到了?屬性注入?之前(通過第三級緩存實(shí)現(xiàn)的),解決了循環(huán)依賴問題。
7.2 為什么不直接使用一級緩存來解決循環(huán)依賴
答:一級緩存中預(yù)期存放的是一個(gè)正常完整的bean,而如果只用一級緩存來解決循環(huán)依賴,那么一級緩存中會在某個(gè)時(shí)間段存在不完整的bean,這是不安全的。
7.3 為什么要使用三級緩存呢?直接使用一級緩存和二級緩存能解決循環(huán)依賴嗎?
答:這個(gè)問題需要結(jié)合為什么引入三級緩存來分析。引用前面的論述,使用一級緩存和二級緩存確實(shí)可以解決循環(huán)依賴,但是這要求每個(gè)原始對象創(chuàng)建出來后就立即生成動態(tài)代理對象(如果有的AOP代理增強(qiáng)話),然后將這個(gè)動態(tài)代理對象放入二級緩存,這就打破了Spring對AOP的設(shè)計(jì)原則,即:在對象初始化完畢后,再去創(chuàng)建代理對象。所以引入三級緩存,并且在三級緩存中存放一個(gè)對象的ObjectFactory,目的就是:延遲代理對象的創(chuàng)建,這里延遲到啥時(shí)候創(chuàng)建呢,有兩種情況:第一種就是確實(shí)存在循環(huán)依賴,那么沒辦法,只能在需要的時(shí)候就創(chuàng)建出來代理對象然后放到二級緩存中,第二種就是不存在循環(huán)依賴,那就應(yīng)該正常地在初始化的后置處理器中創(chuàng)建。
因此不直接使用一級緩存和二級緩存來解決循環(huán)依賴的原因就是:希望在不存在循環(huán)依賴的情況下不破壞Spring對AOP的設(shè)計(jì)原則。
所以總結(jié)來說,如果要使用二級緩存解決循環(huán)依賴,意味著所有Bean在實(shí)例化后就要完成AOP代理,這樣違背了Spring設(shè)計(jì)的原則,Spring在設(shè)計(jì)之初就是通過AnnotationAwareAspectJAutoProxyCreator這個(gè)后置處理器來在Bean生命周期的最后一步來完成AOP代理,而不是在實(shí)例化后就立馬進(jìn)行AOP代理。文章來源:http://www.zghlxwxcb.cn/news/detail-854521.html
參考資料:https://www.cnblogs.com/daimzh/p/13256413.html#!comments文章來源地址http://www.zghlxwxcb.cn/news/detail-854521.html
到了這里,關(guān)于【Spring框架】一篇文章帶你徹底搞懂Spring解決循環(huán)依賴的底層原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!