Spring压轴题:当循环依赖遇上Spring AOP
Spring壓軸題:當(dāng)循環(huán)依賴(lài)遇上Spring AOP
前言
問(wèn):Spring如何解決循環(huán)依賴(lài) ?
答:Spring通過(guò)提前曝光機(jī)制,利用三級(jí)緩存解決循環(huán)依賴(lài)(這原理還是挺簡(jiǎn)單的 ,參考 :三級(jí)緩存、圖解循環(huán)依賴(lài)原理)
再問(wèn) :Spring通過(guò)提前曝光 ,直接曝光到二級(jí)緩存已經(jīng)可以解決循環(huán)依賴(lài)問(wèn)題了,為什么一定要三級(jí)緩存?
再細(xì)問(wèn) :如果循環(huán)依賴(lài)的時(shí)候,所有類(lèi)又都需要Spring AOP自動(dòng)代理,那Spring如何提前曝光 ?曝光的是原始bean還是代理后的bean?
這些問(wèn)題算是Spring源碼的壓軸題了,如果這些問(wèn)題都弄明白,恭喜你順利結(jié)業(yè)Spring源碼了 。就單單對(duì)Spring這一塊的理解,不夸張的說(shuō)可以達(dá)到阿里水準(zhǔn)了
源碼分析
進(jìn)入正題,在Spring創(chuàng)建Bean的核心代碼doGetBean中,在實(shí)例化bean之前,會(huì)先嘗試從三級(jí)緩存獲取bean ,這也是Spring解決循環(huán)依賴(lài)的開(kāi)始
(一) 緩存中獲取bean
// AbstractBeanFactory.javaprotected T doGetBean(final String name, @Nullable final ClassrequiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // 2. 嘗試從緩存中獲取bean Object sharedInstance = getSingleton(beanName); ...} protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 從一級(jí)緩存獲取,key=beanName value=bean Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 從二級(jí)緩存獲取
,key=beanName value=bean singletonObject = this.earlySingletonObjects.get(beanName); // 是否允許循環(huán)引用 if (singletonObject == null && allowEarlyReference) { /** * 三級(jí)緩存獲取,key=beanName value=objectFactory,objectFactory中存儲(chǔ)getObject()方法用于獲取提前曝光的實(shí)例 * * 而為什么不直接將實(shí)例緩存到二級(jí)緩存,而要多此一舉將實(shí)例先封裝到objectFactory中
? * 主要關(guān)鍵點(diǎn)在getObject()方法并非直接返回實(shí)例,而是對(duì)實(shí)例又使用 * SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法對(duì)bean進(jìn)行處理 * * 也就是說(shuō),當(dāng)spring中存在該后置處理器,所有的單例bean在實(shí)例化后都會(huì)被進(jìn)行提前曝光到三級(jí)緩存中, * 但是并不是所有的bean都存在循環(huán)依賴(lài)
,也就是三級(jí)緩存到二級(jí)緩存的步驟不一定都會(huì)被執(zhí)行,有可能曝光后直接創(chuàng)建完成,沒(méi)被提前引用過(guò) , * 就直接被加入到一級(jí)緩存中。因此可以確保只有提前曝光且被引用的bean才會(huì)進(jìn)行該后置處理 */ ObjectFactory<?>singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { /** * 通過(guò)getObject()方法獲取bean