Spring如何利用三級緩存解密解決循環(huán)依賴難題
引言
在Spring框架的日常開發(fā)中,循環(huán)依賴問題如同一個幽靈,時不時困擾著開發(fā)者。當(dāng)Bean A依賴Bean B,而Bean B又依賴Bean A時,傳統(tǒng)的創(chuàng)建流程會陷入死鎖。本文將深入剖析Spring如何通過三級緩存機制破解這一難題,揭示其背后的設(shè)計智慧。
一、循環(huán)依賴的本質(zhì)問題
循環(huán)依賴的根源在于對象創(chuàng)建的順序性矛盾:
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB; // 需要ServiceB實例
}
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA; // 需要ServiceA實例
}
這種"雞生蛋還是蛋生雞"的問題,傳統(tǒng)創(chuàng)建流程無法解決。
二、三級緩存機制全景解析
Spring通過三級緩存架構(gòu)破解循環(huán)依賴:
DefaultSingletonBeanRegistry
-singletonObjects: Map<String, Object> // 一級緩存:成品Bean
-earlySingletonObjects: Map<String, Object> // 二級緩存:半成品(早期引用)
-singletonFactories: Map<String, ObjectFactory> // 三級緩存:對象工廠
各級緩存的核心職責(zé)
| 緩存級別 | 存儲內(nèi)容 | 生命周期 | 作用 |
|---|---|---|---|
| 一級緩存 | 完全初始化的Bean | 應(yīng)用生命周期 | 提供最終產(chǎn)品 |
| 二級緩存 | 早期引用(半成品) | 被依賴→初始化完成 | 臨時周轉(zhuǎn) |
| 三級緩存 | ObjectFactory對象 | 實例化→被依賴/初始化完成 | 延遲生成早期引用 |
三、破解循環(huán)依賴的全流程
以經(jīng)典的A→B→A依賴鏈為例:

關(guān)鍵步驟解析
三級緩存注冊(步驟2/5):
// 實例化后立即注冊 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, bean));
早期引用生成(步驟9-11):
protected Object getEarlyBeanReference(String beanName, Object bean) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
// 動態(tài)決策是否創(chuàng)建代理
bean = ((SmartInstantiationAwareBeanPostProcessor) bp)
.getEarlyBeanReference(bean, beanName);
}
}
return bean;
}
緩存狀態(tài)轉(zhuǎn)移(步驟12/16/20):
- 被依賴后從三級緩存刪除
- 初始化完成后從二級緩存刪除
- 最終成品存于一級緩存
四、三級緩存的設(shè)計精妙之處
1. 雙重延遲決策機制
public Object getEarlyBeanReference() {
// 延遲點1:只在被依賴時觸發(fā)
// 延遲點2:動態(tài)決定是否創(chuàng)建代理
return (needsProxy ? createProxy(bean) : bean);
}
優(yōu)勢:避免為不需要代理或未發(fā)生循環(huán)依賴的Bean創(chuàng)建額外對象
2. 狀態(tài)完整性保障

當(dāng)創(chuàng)建代理時,Bean已通過populateBean()完成屬性注入,避免NPE風(fēng)險
3. 對象版本統(tǒng)一性
// 最終代理一致性保證
public void initializeBean() {
if (earlyProxyReference != null) {
return earlyProxyReference; // 復(fù)用已創(chuàng)建的代理
}
return createProxy(bean); // 無循環(huán)依賴時創(chuàng)建
}
4. 資源高效利用
| 場景 | 傳統(tǒng)方案 | 三級緩存方案 | 性能提升 |
|---|---|---|---|
| 無循環(huán)依賴 | 創(chuàng)建所有代理 | 不創(chuàng)建代理 | 節(jié)省90%內(nèi)存 |
| 有循環(huán)依賴無代理 | 創(chuàng)建半成品副本 | 直接使用原始對象 | 減少對象創(chuàng)建 |
| 有循環(huán)依賴需代理 | 可能創(chuàng)建多個代理 | 單例代理 | 避免代理沖突 |
五、疑難場景解決方案
1. 代理對象循環(huán)依賴
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional // 需要代理
public void createUser() {...}
}
解決方案:
- 在
getEarlyBeanReference()中創(chuàng)建代理 - 保證代理對象基于完成屬性注入的狀態(tài)
2. 多級循環(huán)依賴
A→B→C→A依賴鏈:

處理流程:
- C獲取A時觸發(fā)三級緩存
- 返回A的早期引用
- C完成初始化
- B獲得C的引用
- A最終獲得B的引用
3. 無法解決的場景
| 場景 | 原因 |
|---|---|
| 構(gòu)造器循環(huán)依賴 | 對象未實例化完成,無法暴露引用 |
| 原型(Prototype)作用域 | Spring不緩存原型Bean |
| @Async方法 | 代理生成時機與標(biāo)準(zhǔn)AOP不同 |
六、性能優(yōu)化建議
避免循環(huán)依賴:重構(gòu)設(shè)計,引入事件機制
// 使用事件解耦 applicationContext.publishEvent(new UserCreatedEvent(user));
懶加載優(yōu)化:
@Lazy @Autowired private HeavyService heavyService; // 延遲初始化
作用域控制:
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {...}
結(jié)論
Spring的三級緩存機制通過以下創(chuàng)新設(shè)計解決循環(huán)依賴:
- 空間換時間:通過三級緩存狀態(tài)管理打破創(chuàng)建順序限制
- 延遲決策:在被依賴時才決定是否創(chuàng)建代理
- 狀態(tài)保障:確保代理對象基于完整初始化狀態(tài)
- 資源優(yōu)化:避免不必要的對象創(chuàng)建
理解三級緩存不僅幫助解決循環(huán)依賴異常,更是深入掌握Spring框架設(shè)計思想的鑰匙。正如Spring框架創(chuàng)始人Rod Johnson所說:"好的框架設(shè)計是在約束與靈活性之間找到完美平衡",三級緩存正是這種平衡的藝術(shù)體現(xiàn)。
到此這篇關(guān)于Spring如何利用三級緩存解密解決循環(huán)依賴難題的文章就介紹到這了,更多相關(guān)Spring三級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot整合企業(yè)微信機器人助手推送消息的實現(xiàn)
本文主要介紹了Springboot整合企業(yè)微信機器人助手推送消息的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
Java使用easypoi快速導(dǎo)入導(dǎo)出的實現(xiàn)
這篇文章主要介紹了實現(xiàn)Java使用easypoi快速導(dǎo)入導(dǎo)出的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03
java中ConcurrentHashMap的讀操作為什么不需要加鎖
ConcurrentHashMap完全允許多個讀操作并發(fā)進(jìn)行,讀操作并不需要加鎖。所以下面這篇文章主要給大家介紹了關(guān)于java中ConcurrentHashMap的讀操作為什么不需要加鎖的相關(guān)資料,需要的朋友可以參考下2018-10-10

