此處是我自己的一個(gè)理解,防止以后忘記,如若那個(gè)地方理解不對(duì),歡迎指出。
一、背景
在我們寫代碼的過程中一般會(huì)使用 @Autowired 來注入另外的一個(gè)對(duì)象,但有些時(shí)候發(fā)生了循環(huán)依賴,但是我們的代碼沒有報(bào)錯(cuò),這個(gè)是什么原因呢?
二、前置知識(shí)
1、考慮循環(huán)依賴的類型
此處我們考慮 單例 + @Autowired 的循環(huán)依賴,不考慮使用構(gòu)造器注入或原型作用域的Bean的注入。
2、代理對(duì)象何時(shí)創(chuàng)建

注意:
正常情況下,即沒有發(fā)生 循環(huán)依賴的時(shí)候,aop增強(qiáng)是在 bean 初始化完成之后的 BeanPostProcessor#postProcessAfterInitialization方法中,但是如果有循環(huán)依賴發(fā)生的話,就需要提前,在 getEarlyBeanReference中提前創(chuàng)建代理對(duì)象。
3、3級(jí)緩存中保存的是什么對(duì)象
| 緩存字段名 | 緩存級(jí)別 | 數(shù)據(jù)類型 | 解釋 |
|---|---|---|---|
| singletonObjects | 1 | Map<String, Object> | 保存的是完整的Bean,即可以使用的Bean |
| earlySingletonObjects | 2 | Map<String, Object> | 保存的是半成品的Bean,即屬性還沒有設(shè)置,沒有完成初始化工作 |
| singletonFactories | 3 | Map<String, ObjectFactory<?>> | 主要是生成Bean,然后放到二級(jí)緩存中 |
注意:
ObjectFactory#getObject() 每調(diào)用一次,都會(huì)產(chǎn)生一個(gè)新的對(duì)象或返回舊對(duì)象,取決于是否存在代理等等。

4、從3級(jí)緩存中獲取對(duì)象
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

5 Spring Bean的簡(jiǎn)化創(chuàng)建過程
1、實(shí)例化一個(gè)bean
Object bean = instanceWrapper.getWrappedInstance();
實(shí)例化Bean 即 new Bean()
2、加入到三級(jí)緩存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
加入到三級(jí)緩存中是有一些條件判斷的,一般都會(huì)是成立的,此處認(rèn)為需要加入到三級(jí)緩存。
3、設(shè)置bean的屬性
populateBean(beanName, mbd, instanceWrapper);
第一步實(shí)例化了bean,但是此時(shí)是沒有填充需要注入的屬性的,通過這一步進(jìn)行屬性的填充。
4、初始化bean
Object exposedObject = initializeBean(beanName, exposedObject, mbd);
初始化Bean,執(zhí)行初始化方法、Aware回調(diào)、執(zhí)行 BeanPostProcessor#postProcessAfterInitialization 方法 (aop的增強(qiáng)是在這個(gè)里面實(shí)現(xiàn)的)
如果有循環(huán)引用的話,則aop的增強(qiáng)需要提前。
5、加入到一級(jí)緩存中
addSingleton(......)
三、理解
@Component
class A {
@Autowired
private B b;
}
@Transaction (存在代理)
@Component
class B{
@Autowired
private A a;
}
1、假設(shè)只有singletonObjects和earlySingletonObjects可否完成循環(huán)依賴
| 緩存字段名 | 緩存級(jí)別 | 數(shù)據(jù)類型 | 解釋 |
|---|---|---|---|
| singletonObjects | 1 | Map<String, Object> | 保存的是完整的Bean,即可以使用的Bean |
| earlySingletonObjects | 2 | Map<String, Object> | 保存的是半成品的Bean,即屬性還沒有設(shè)置,沒有完成初始化工作 |
此時(shí)需要獲取 B的實(shí)例,即 getBean("b"),由上方了解到的 Bean 的簡(jiǎn)化流程可知


由上圖可知,對(duì)象存在代理時(shí),2級(jí)緩存無法解決問題。因?yàn)榇韺?duì)象是通過BeanPostProcessor來完成,是在設(shè)置屬性之后才產(chǎn)生的代理對(duì)象。
此時(shí)可能有人會(huì)說,那如果我在構(gòu)建完B的實(shí)例后,就立馬進(jìn)行Aop代理,這樣不就解決問題了嗎?那假設(shè)A和B之間沒有發(fā)生循環(huán)依賴,這樣設(shè)計(jì)會(huì)不會(huì)不優(yōu)雅?
2、假設(shè)只有singletonObjects和singletonFactories可否完成循環(huán)依賴

由圖中可知也是不可以實(shí)現(xiàn)的。
3、3級(jí)緩存如何實(shí)現(xiàn)
1、解決代理問題
因?yàn)槟J(rèn)情況下,代理是通過BeanPostProcessor來完成,為了解決代理,就需要提前創(chuàng)建代理,那么這個(gè)代理的創(chuàng)建就放到3級(jí)緩存中來進(jìn)行創(chuàng)建。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
getEarlyBeanReference 此方法會(huì)返回代理bean
2、解決單例通過第3級(jí)緩存多次獲取的值不一致

從上圖中可知,對(duì)象是先從 一級(jí)->二級(jí)->三級(jí)緩存 這樣查找,當(dāng)三級(jí)緩存產(chǎn)生了對(duì)象后就放入二級(jí)緩存中緩存起來,同時(shí)刪除三級(jí)緩存。
3、流程圖

四、總結(jié)
1、一級(jí)緩存 singletonObjects 存放可以使用的單例。
2、二級(jí)緩存earlySingletonObjects存放的是早期的Bean,即是半成品,此時(shí)還是不可用的。
3、三級(jí)緩存singletonFactories 是一個(gè)對(duì)象工廠,用于創(chuàng)建對(duì)象,然后放入到二級(jí)緩存中。同時(shí)對(duì)象如果有Aop代理的話,這個(gè)對(duì)對(duì)象工廠返回的就是代理對(duì)象。
那可以在earlySingletonObjects中直接存放創(chuàng)建后的代理對(duì)象嗎?這樣是可以解決問題,但是設(shè)計(jì)可能就不合理了。因?yàn)樵赟pring中 Aop的代理是在對(duì)象完成之后創(chuàng)建的。而且如果沒有發(fā)生循環(huán)依賴的話,有必要提前創(chuàng)建代理對(duì)象嗎?分成三級(jí)緩存,代碼結(jié)構(gòu)更清楚,更合理。