Spring使用三級(jí)緩存解決循環(huán)依賴的問(wèn)題
Spring如何使用三級(jí)緩存解決循環(huán)依賴在沒(méi)開(kāi)始文章之前首先來(lái)了解一下什么是循環(huán)依賴
@Component
public class A {
@Autowired
B b;
}
@Component
public class B {
@Autowired
A a;
}
在對(duì)象A創(chuàng)建過(guò)程中,需要注入B,因?yàn)槿萜髦袥](méi)有B,則去創(chuàng)建B,B創(chuàng)建過(guò)程中又需要注入A,而A在等待B的創(chuàng)建,B在等待A的創(chuàng)建,導(dǎo)致兩者都無(wú)法創(chuàng)建成功,無(wú)法加入到單例池供用戶使用。
Spring則通過(guò)三級(jí)緩存來(lái)解決循環(huán)依賴的問(wèn)題,另外如果對(duì)象的作用范圍是Prototype,則無(wú)法通過(guò)三級(jí)緩存解決循環(huán)依賴,會(huì)拋出BeanCurrentlyInCreationException異常,構(gòu)造注入的方式,也無(wú)法解決循環(huán)依賴,只有set注入可以解決。
那么三級(jí)緩存又是什么呢?
三級(jí)緩存就是三個(gè)Map
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
//一級(jí)緩存(單例池,經(jīng)過(guò)完成生命周期的對(duì)象會(huì)放入其中)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//二級(jí)緩存(剛實(shí)例化還未初始化的原始對(duì)象會(huì)放入其中)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//三級(jí)緩存(存放創(chuàng)建某個(gè)對(duì)象的工廠)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
Spring Bean對(duì)象從創(chuàng)建到初始化大致會(huì)經(jīng)過(guò)四個(gè)流程
getSingleton()、doCreateBean()、populateBean()、addSingleton()
getSingleton:從單例池中獲取bean對(duì)象,如果沒(méi)有,則進(jìn)行創(chuàng)建doCreateBean():創(chuàng)建bean對(duì)象populateBean():填充依賴,如果被填充的對(duì)象不存在于單例池,則進(jìn)行創(chuàng)建等四個(gè)流程addSingleton():將初始化完成的對(duì)象加入到單例池
循環(huán)依賴的對(duì)象在三級(jí)緩存中的遷移過(guò)程
- A 創(chuàng)建過(guò)程中需要 B, 于是 A 將自己放到三級(jí)緩存里面,去實(shí)例化 B
- B 實(shí)例化的時(shí)候發(fā)現(xiàn)需要 A,于是 B 先查一級(jí)緩存,沒(méi)有,再查二級(jí)緩存,還是沒(méi)有,再查三級(jí)緩存
- 找到了A,然后把三級(jí)緩存中的 A 放到二級(jí)緩存,并刪除三級(jí)緩存中的 A
- B 順利初始化完畢,將自己放到一級(jí)緩存中(此時(shí) B 中的 A 還是創(chuàng)建中狀態(tài),并沒(méi)有完全初始化),刪除三級(jí)緩存中的 B
然后接著回來(lái)創(chuàng)建 A,此時(shí) B 已經(jīng)完成創(chuàng)建,直接從一級(jí)緩存中拿到 B,完成 A 的創(chuàng)建,并將 A 添加到單例池,刪除二級(jí)緩存中的 A
圖示:

以上就是Spring使用三級(jí)緩存解決循環(huán)依賴的詳細(xì)內(nèi)容,更多關(guān)于Spring循環(huán)依賴的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
mybatis的大于小于號(hào)轉(zhuǎn)義符號(hào)一覽
這篇文章主要介紹了mybatis的大于小于號(hào)轉(zhuǎn)義符號(hào)一覽,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java中的延遲隊(duì)列DelayQueue詳細(xì)解析
這篇文章主要介紹了Java中的延遲隊(duì)列DelayQueue詳細(xì)解析,JDK自身支持延遲隊(duì)列的數(shù)據(jù)結(jié)構(gòu),其實(shí)類:java.util.concurrent.DelayQueue,<BR>我們通過(guò)閱讀源碼的方式理解該延遲隊(duì)列類的實(shí)現(xiàn)過(guò)程,需要的朋友可以參考下2023-12-12
Spring中的DeferredImportSelector實(shí)現(xiàn)詳解
這篇文章主要介紹了Spring中的DeferredImportSelector實(shí)現(xiàn)詳解,兩個(gè)官方的實(shí)現(xiàn)類AutoConfigurationImportSelector和ImportAutoConfigurationImportSelector都是Spring Boot后新增的實(shí)現(xiàn),需要的朋友可以參考下2024-01-01
深入探討Druid動(dòng)態(tài)數(shù)據(jù)源的實(shí)現(xiàn)方式
Druid是一個(gè)高性能的實(shí)時(shí)分析數(shù)據(jù)庫(kù),它可以處理大規(guī)模數(shù)據(jù)集的快速查詢和聚合操作,在Druid中,動(dòng)態(tài)數(shù)據(jù)源是一種可以在運(yùn)行時(shí)動(dòng)態(tài)添加和刪除的數(shù)據(jù)源,使用動(dòng)態(tài)數(shù)據(jù)源,您可以在Druid中輕松地處理不斷變化的數(shù)據(jù)集,本文講給大家介紹一下Druid動(dòng)態(tài)數(shù)據(jù)源該如何實(shí)現(xiàn)2023-08-08
Spring高級(jí)注解@PropertySource詳細(xì)解讀
這篇文章主要介紹了Spring高級(jí)注解@PropertySource詳細(xì)解讀,@PropertySource注解用于指定資源文件讀取的位置,它不僅能讀取properties文件,也能讀取xml文件,并且通過(guò)YAML解析器,配合自定義PropertySourceFactory實(shí)現(xiàn)解析yaml文件,需要的朋友可以參考下2023-11-11

