Spring解決循環(huán)依賴
Spring通過三級緩存來解決循環(huán)依賴懊纳,一級緩存為單例池(singletonObjects)掸掸,二級緩存為早期曝光對象(earlySingletonObjects)驼修,三級緩存為早期曝光對象工廠(singletonFactories)籍胯。
當(dāng)A冗懦、B兩個類發(fā)送循環(huán)引用時谬运,在A完成實例化后隙赁,就使用實例化后的對象去創(chuàng)建一個對象工廠,添加到三級緩存中梆暖,如果A被AOP代理伞访,那么通過這個工廠獲取到的就是A代理后的對象,如果A沒有被AOP代理轰驳,那么這個工廠獲取到的就是A實例化的對象厚掷。
當(dāng)A進(jìn)行屬性注入時,會去創(chuàng)建B级解,同時B又依賴了A冒黑,所以創(chuàng)建B的同時會去調(diào)用getBean(a)來獲取需要的依賴,此時的getBean(a)會從緩存中獲惹诨:
- 先獲取到三級緩存中的工廠
- 調(diào)用工廠的getObject方法來獲取對應(yīng)的對象抡爹,得到這個對象后將其注入到B中,緊接著B會走完它的生命周期流程芒划,包含初始化豁延、后置處理器等。
- 當(dāng)B創(chuàng)建完后腊状,會將B再注入到A中,此時A再完成它的整個生命周期苔可。
Spring循環(huán)依賴進(jìn)階
一個對象創(chuàng)建過程由3部分組成:
- 實例化:就是new一個對象
- 屬性注入:為new出來的對象填充屬性
- 初始化:執(zhí)行aware接口中的方法缴挖,初始化方法,完成AOP代理
Spring三級緩存
- singletonObjects:一級緩存焚辅,存儲的是所有創(chuàng)建好了的單例Bean
- earlySingletonObjects:二級緩存映屋,完成實例化苟鸯,但是還未進(jìn)行屬性注入及初始化的對象
- singletonFactories:三級緩存,提前暴露一個單例工廠棚点,二級緩存中存儲的就是這個工廠中獲取到的對象
普通循環(huán)依賴與帶AOP循環(huán)依賴
普通循環(huán)依賴與帶AOP循環(huán)依賴幾乎一樣早处,只是在三級緩存中存放的是函數(shù)式接口,在需要調(diào)用時直接返回代理對象瘫析。三級緩存存在的意義:
只有真正發(fā)生循環(huán)依賴的時候砌梆,才去提前生成代理對象,否則只會創(chuàng)建一個工廠并將其放入到三級緩存中贬循,但是不會去通過這個工廠去真正創(chuàng)建對象
普通循環(huán)依賴
帶AOP的循環(huán)依賴
是否可以用二級緩存而不用三級緩存咸包?
答案:不可以,違背Spring在結(jié)合AOP跟Bean的生命周期的設(shè)計杖虾!Spring結(jié)合AOP跟Bean的生命周期(看下圖)本身就是通過AnnotationAwareAspectJAutoProxyCreator這個后置處理器來完成的烂瘫,在這個后置處理的postProcessAfterInitialization方法中對初始化后的Bean完成AOP代理。如果出現(xiàn)了循環(huán)依賴奇适,那沒有辦法坟比,只有給Bean先創(chuàng)建代理,但是沒有出現(xiàn)循環(huán)依賴的情況下嚷往,設(shè)計之初就是讓Bean在生命周期的「最后一步完成代理而不是在實例化后就立馬完成代理」葛账。
使用三級緩存的情況下,A间影、B的創(chuàng)建流程
不使用三級緩存注竿,直接在二級緩存中
結(jié)論:上面兩個流程的唯一區(qū)別在于為A對象創(chuàng)建代理的時機(jī)不同,使用三級緩存的情況下為A創(chuàng)建代理的時機(jī)是在B中需要注入A的時候魂贬,而不使用三級緩存的話在A實例化后就需要馬上為A創(chuàng)建代理然后放入到二級緩存中去巩割。三級緩存是無法提速的!
為什么要使用三級緩存付燥,二級緩存解決不了循環(huán)依賴嗎
如果使用二級緩存解決循環(huán)依賴,意味著所有Bean在實例化后就要完成AOP代理键科,這樣違背了Spring設(shè)計的原則,Spring在設(shè)計之初就是通過AnnotationAwareAspectJAutoProxyCreator這個后置處理器在Bean生命周期的最后一步來完成AOP代理勋颖,而不是在實例化后立馬進(jìn)行AOP代理。