欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring如何利用三級(jí)緩存解密解決循環(huán)依賴難題

 更新時(shí)間:2025年07月23日 09:43:11   作者:佛祖讓我來巡山  
在Spring框架的日常開發(fā)中,循環(huán)依賴問題如同一個(gè)幽靈,時(shí)不時(shí)困擾著開發(fā)者,本文將深入剖析Spring如何通過三級(jí)緩存機(jī)制破解這一難題,希望對(duì)大家有所幫助

引言

在Spring框架的日常開發(fā)中,循環(huán)依賴問題如同一個(gè)幽靈,時(shí)不時(shí)困擾著開發(fā)者。當(dāng)Bean A依賴Bean B,而Bean B又依賴Bean A時(shí),傳統(tǒng)的創(chuàng)建流程會(huì)陷入死鎖。本文將深入剖析Spring如何通過三級(jí)緩存機(jī)制破解這一難題,揭示其背后的設(shè)計(jì)智慧。

一、循環(huán)依賴的本質(zhì)問題

循環(huán)依賴的根源在于對(duì)象創(chuàng)建的順序性矛盾

@Component
public class ServiceA {
    @Autowired
    private ServiceB serviceB; // 需要ServiceB實(shí)例
}

@Component
public class ServiceB {
    @Autowired
    private ServiceA serviceA; // 需要ServiceA實(shí)例
}

這種"雞生蛋還是蛋生雞"的問題,傳統(tǒng)創(chuàng)建流程無法解決。

二、三級(jí)緩存機(jī)制全景解析

Spring通過三級(jí)緩存架構(gòu)破解循環(huán)依賴:

DefaultSingletonBeanRegistry

-singletonObjects: Map<String, Object> // 一級(jí)緩存:成品Bean

-earlySingletonObjects: Map<String, Object> // 二級(jí)緩存:半成品(早期引用)

-singletonFactories: Map<String, ObjectFactory> // 三級(jí)緩存:對(duì)象工廠

各級(jí)緩存的核心職責(zé)

緩存級(jí)別存儲(chǔ)內(nèi)容生命周期作用
一級(jí)緩存完全初始化的Bean應(yīng)用生命周期提供最終產(chǎn)品
二級(jí)緩存早期引用(半成品)被依賴→初始化完成臨時(shí)周轉(zhuǎn)
三級(jí)緩存ObjectFactory對(duì)象實(shí)例化→被依賴/初始化完成延遲生成早期引用

三、破解循環(huán)依賴的全流程

以經(jīng)典的A→B→A依賴鏈為例:

關(guān)鍵步驟解析

三級(jí)緩存注冊(cè)(步驟2/5):

// 實(shí)例化后立即注冊(cè)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, bean));

早期引用生成(步驟9-11):

protected Object getEarlyBeanReference(String beanName, Object bean) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            // 動(dòng)態(tài)決策是否創(chuàng)建代理
            bean = ((SmartInstantiationAwareBeanPostProcessor) bp)
                       .getEarlyBeanReference(bean, beanName);
        }
    }
    return bean;
}

緩存狀態(tài)轉(zhuǎn)移(步驟12/16/20):

  • 被依賴后從三級(jí)緩存刪除
  • 初始化完成后從二級(jí)緩存刪除
  • 最終成品存于一級(jí)緩存

四、三級(jí)緩存的設(shè)計(jì)精妙之處

1. 雙重延遲決策機(jī)制

public Object getEarlyBeanReference() {
    // 延遲點(diǎn)1:只在被依賴時(shí)觸發(fā)
    // 延遲點(diǎn)2:動(dòng)態(tài)決定是否創(chuàng)建代理
    return (needsProxy ? createProxy(bean) : bean); 
}

優(yōu)勢(shì):避免為不需要代理或未發(fā)生循環(huán)依賴的Bean創(chuàng)建額外對(duì)象

2. 狀態(tài)完整性保障

當(dāng)創(chuàng)建代理時(shí),Bean已通過populateBean()完成屬性注入,避免NPE風(fēng)險(xiǎn)

3. 對(duì)象版本統(tǒng)一性

// 最終代理一致性保證
public void initializeBean() {
    if (earlyProxyReference != null) {
        return earlyProxyReference; // 復(fù)用已創(chuàng)建的代理
    }
    return createProxy(bean); // 無循環(huán)依賴時(shí)創(chuàng)建
}

4. 資源高效利用

場景傳統(tǒng)方案三級(jí)緩存方案性能提升
無循環(huán)依賴創(chuàng)建所有代理不創(chuàng)建代理節(jié)省90%內(nèi)存
有循環(huán)依賴無代理創(chuàng)建半成品副本直接使用原始對(duì)象減少對(duì)象創(chuàng)建
有循環(huán)依賴需代理可能創(chuàng)建多個(gè)代理單例代理避免代理沖突

五、疑難場景解決方案

1. 代理對(duì)象循環(huán)依賴

@Service
public class UserService {
    @Autowired 
    private OrderService orderService;
    
    @Transactional // 需要代理
    public void createUser() {...}
}

解決方案

  • getEarlyBeanReference()中創(chuàng)建代理
  • 保證代理對(duì)象基于完成屬性注入的狀態(tài)

2. 多級(jí)循環(huán)依賴

A→B→C→A依賴鏈:

處理流程

  • C獲取A時(shí)觸發(fā)三級(jí)緩存
  • 返回A的早期引用
  • C完成初始化
  • B獲得C的引用
  • A最終獲得B的引用

3. 無法解決的場景

場景原因
構(gòu)造器循環(huán)依賴對(duì)象未實(shí)例化完成,無法暴露引用
原型(Prototype)作用域Spring不緩存原型Bean
@Async方法代理生成時(shí)機(jī)與標(biāo)準(zhǔn)AOP不同

六、性能優(yōu)化建議

避免循環(huán)依賴:重構(gòu)設(shè)計(jì),引入事件機(jī)制

// 使用事件解耦
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的三級(jí)緩存機(jī)制通過以下創(chuàng)新設(shè)計(jì)解決循環(huán)依賴:

  • 空間換時(shí)間:通過三級(jí)緩存狀態(tài)管理打破創(chuàng)建順序限制
  • 延遲決策:在被依賴時(shí)才決定是否創(chuàng)建代理
  • 狀態(tài)保障:確保代理對(duì)象基于完整初始化狀態(tài)
  • 資源優(yōu)化:避免不必要的對(duì)象創(chuàng)建

理解三級(jí)緩存不僅幫助解決循環(huán)依賴異常,更是深入掌握Spring框架設(shè)計(jì)思想的鑰匙。正如Spring框架創(chuàng)始人Rod Johnson所說:"好的框架設(shè)計(jì)是在約束與靈活性之間找到完美平衡",三級(jí)緩存正是這種平衡的藝術(shù)體現(xiàn)。

到此這篇關(guān)于Spring如何利用三級(jí)緩存解密解決循環(huán)依賴難題的文章就介紹到這了,更多相關(guān)Spring三級(jí)緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java界面編程實(shí)現(xiàn)界面跳轉(zhuǎn)

    Java界面編程實(shí)現(xiàn)界面跳轉(zhuǎn)

    這篇文章主要為大家詳細(xì)介紹了Java界面編程實(shí)現(xiàn)界面跳轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 解決程序啟動(dòng)報(bào)錯(cuò)org.springframework.context.ApplicationContextException: Unable to start web server問題

    解決程序啟動(dòng)報(bào)錯(cuò)org.springframework.context.ApplicationContextExcept

    文章描述了一個(gè)Spring Boot項(xiàng)目在不同環(huán)境下啟動(dòng)時(shí)出現(xiàn)差異的問題,通過分析報(bào)錯(cuò)信息,發(fā)現(xiàn)是由于導(dǎo)入`spring-boot-starter-tomcat`依賴時(shí)定義的scope導(dǎo)致的配置問題,調(diào)整依賴導(dǎo)入配置后,解決了啟動(dòng)錯(cuò)誤
    2024-11-11
  • Mybatis 查詢語句條件為枚舉類型時(shí)報(bào)錯(cuò)的解決

    Mybatis 查詢語句條件為枚舉類型時(shí)報(bào)錯(cuò)的解決

    這篇文章主要介紹了Mybatis 查詢語句條件為枚舉類型時(shí)報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 利用Java實(shí)現(xiàn)天氣預(yù)報(bào)播報(bào)功能

    利用Java實(shí)現(xiàn)天氣預(yù)報(bào)播報(bào)功能

    這篇文章主要為大家介紹了如何利用Java語言實(shí)現(xiàn)天氣預(yù)報(bào)播報(bào)功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定的幫助,需要的可以參考一下
    2022-06-06
  • MybatisPlus分頁失效不起作用的解決

    MybatisPlus分頁失效不起作用的解決

    在使用MybatisPlus的selectPage時(shí)發(fā)現(xiàn)分頁不起作用,每次返回的都是全部的數(shù)據(jù),本文就來介紹一下MybatisPlus分頁失效不起作用的解決,感興趣的可以了解一下
    2024-03-03
  • Mybatis查詢方法如何實(shí)現(xiàn)沒有返回值

    Mybatis查詢方法如何實(shí)現(xiàn)沒有返回值

    這篇文章主要介紹了Mybatis查詢方法如何實(shí)現(xiàn)沒有返回值,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • JUC之CountdownLatch使用詳解

    JUC之CountdownLatch使用詳解

    這篇文章主要介紹了JUC之CountdownLatch使用詳解,CountdownLatch 用來進(jìn)行線程同步協(xié)作,等待所有線程完成倒計(jì)時(shí),
    其中構(gòu)造參數(shù)用來初始化等待計(jì)數(shù)值,await() 用來等待計(jì)數(shù)歸零,countDown() 用來讓計(jì)數(shù)減一,需要的朋友可以參考下
    2023-12-12
  • 詳解Spring Cloud Zuul中路由配置細(xì)節(jié)

    詳解Spring Cloud Zuul中路由配置細(xì)節(jié)

    本篇文章主要介紹了詳解Spring Cloud Zuul中路由配置細(xì)節(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • 圖文詳解Java中的字節(jié)輸入與輸出流

    圖文詳解Java中的字節(jié)輸入與輸出流

    在Java中所有數(shù)據(jù)都是使用流讀寫的,流是一組有序的數(shù)據(jù)序列,將數(shù)據(jù)從一個(gè)地方帶到另一個(gè)地方,這篇文章主要給大家介紹了關(guān)于Java中字節(jié)輸入與輸出流的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • 手把手教你使用IDEA創(chuàng)建多模塊(maven)項(xiàng)目

    手把手教你使用IDEA創(chuàng)建多模塊(maven)項(xiàng)目

    這篇文章主要給大家介紹了關(guān)于如何使用IDEA創(chuàng)建多模塊(maven)項(xiàng)目的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07

最新評(píng)論