最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入剖析Spring如何解決循環(huán)依賴

 更新時間:2025年04月04日 08:15:59   作者:北辰alk  
循環(huán)依賴(Circular?Dependency)是指兩個或多個Bean相互依賴,形成一個閉環(huán)的情況,本文將和大家深入探討一下Spring如何解決循環(huán)依賴,需要的可以參考下

一、什么是循環(huán)依賴

循環(huán)依賴(Circular Dependency)是指兩個或多個Bean相互依賴,形成一個閉環(huán)的情況。例如:

@Service
public class AService {
    @Autowired
    private BService bService;
}

@Service
public class BService {
    @Autowired
    private AService aService;
}

上述代碼中,AService依賴BService,而BService又依賴AService,形成了循環(huán)依賴。

二、Spring循環(huán)依賴的三種情況

構(gòu)造器循環(huán)依賴:通過構(gòu)造器注入形成的循環(huán)依賴,Spring無法解決,會直接拋出BeanCurrentlyInCreationException

Setter循環(huán)依賴(單例模式):通過setter方法注入形成的循環(huán)依賴,Spring可以解決
原型模式(prototype)循環(huán)依賴:scope為prototype的bean形成的循環(huán)依賴,Spring無法解決

三、Spring解決循環(huán)依賴的核心思想

Spring通過三級緩存機制來解決單例模式下的Setter循環(huán)依賴問題。核心思想是:

提前暴露未完全初始化的Bean實例:在Bean創(chuàng)建過程中,在完成實例化后、初始化前,將Bean的引用提前暴露

分級緩存:使用三級緩存存儲不同狀態(tài)的Bean,確保依賴注入時能獲取到正確的引用

四、三級緩存詳解

1. 三級緩存結(jié)構(gòu)

/** 一級緩存:存放完全初始化好的Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 二級緩存:存放原始的Bean對象(尚未填充屬性) */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** 三級緩存:存放Bean工廠對象,用于生成原始Bean對象 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

2. Bean創(chuàng)建與三級緩存交互流程

1.創(chuàng)建Bean實例:通過反射調(diào)用構(gòu)造器創(chuàng)建Bean實例

2.放入三級緩存:將Bean包裝成ObjectFactory并放入三級緩存singletonFactories

3.屬性填充:填充Bean的屬性,此時如果發(fā)現(xiàn)依賴其他Bean

  • 從一級緩存singletonObjects獲取
  • 如果不存在,嘗試從二級緩存earlySingletonObjects獲取
  • 如果還不存在,從三級緩存singletonFactories獲取ObjectFactory并生成Bean,然后放入二級緩存

4.初始化:執(zhí)行初始化方法(@PostConstruct等)

5.放入一級緩存:將完全初始化好的Bean放入一級緩存,刪除二、三級緩存中的記錄

3. 循環(huán)依賴解決示例

以AService和BService的循環(huán)依賴為例:

1.開始創(chuàng)建AService

  • 實例化AService
  • 將AService的ObjectFactory放入三級緩存

2.填充AService屬性時發(fā)現(xiàn)需要BService

  • 開始創(chuàng)建BService
  • 實例化BService
  • 將BService的ObjectFactory放入三級緩存

3.填充BService屬性時發(fā)現(xiàn)需要AService

  • 從一級緩存獲取AService → 不存在
  • 從二級緩存獲取AService → 不存在
  • 從三級緩存獲取AService的ObjectFactory → 存在,生成AService早期引用并放入二級緩存
  • 將AService早期引用注入BService

4.BService繼續(xù)完成屬性填充和初始化

5.BService創(chuàng)建完成,放入一級緩存

6.AService獲得完全初始化的BService引用

7.AService繼續(xù)完成屬性填充和初始化

8.AService創(chuàng)建完成,放入一級緩存

五、源碼分析

關(guān)鍵源碼在DefaultSingletonBeanRegistry類中:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 1. 先從一級緩存獲取
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 2. 從二級緩存獲取
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 3. 從三級緩存獲取ObjectFactory
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    // 將三級緩存提升到二級緩存
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

六、為什么構(gòu)造器循環(huán)依賴無法解決

時序問題:構(gòu)造器注入發(fā)生在實例化階段,此時Bean尚未創(chuàng)建完成,無法提前暴露引用

緩存機制不適用:三級緩存機制依賴于在實例化后、初始化前暴露引用,而構(gòu)造器注入時連實例都還沒完全創(chuàng)建

七、為什么原型模式的循環(huán)依賴無法解決

生命周期不同:原型模式每次獲取都創(chuàng)建新實例,Spring不緩存原型Bean

無法提前暴露引用:沒有緩存機制支持,無法在創(chuàng)建過程中共享未完成初始化的引用

八、Spring解決循環(huán)依賴的局限性

只能解決單例模式的Setter注入循環(huán)依賴

大量使用循環(huán)依賴會導致代碼結(jié)構(gòu)混亂,增加維護難度

某些AOP場景下可能出現(xiàn)問題(需要特殊處理)

九、最佳實踐

避免循環(huán)依賴:通過設(shè)計模式(如中介者模式、觀察者模式)重構(gòu)代碼

使用Setter注入替代構(gòu)造器注入:如果必須使用循環(huán)依賴

使用@Lazy注解:延遲加載依賴的Bean

@Service
public class AService {
    @Autowired
    @Lazy
    private BService bService;
}

使用ApplicationContextAware接口:手動獲取依賴Bean

十、總結(jié)

Spring通過三級緩存機制巧妙地解決了單例模式下Setter注入的循環(huán)依賴問題,但其本質(zhì)上是一種妥協(xié)方案。良好的系統(tǒng)設(shè)計應(yīng)當盡量避免循環(huán)依賴,保持清晰的依賴關(guān)系。理解Spring解決循環(huán)依賴的機制,有助于我們更好地使用Spring框架,并在遇到相關(guān)問題時能夠快速定位和解決。

到此這篇關(guān)于深入剖析Spring如何解決循環(huán)依賴的文章就介紹到這了,更多相關(guān)Spring解決循環(huán)依賴內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java Socket長連接實現(xiàn)教程及標準示例

    Java Socket長連接實現(xiàn)教程及標準示例

    Java Socket長連接提供了一種持久通信方式,適用于需要低延遲和高效率的網(wǎng)絡(luò)應(yīng)用,本文將詳細介紹如何創(chuàng)建Java Socket長連接的客戶端和服務(wù)端,包括它們的工作原理、實現(xiàn)細節(jié)、異常處理以及性能優(yōu)化,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • Java多線程面試題之交替輸出問題的實現(xiàn)

    Java多線程面試題之交替輸出問題的實現(xiàn)

    本文主要介紹了Java多線程面試題之交替輸出問題的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 詳解java==運算符和equals()方法的區(qū)別

    詳解java==運算符和equals()方法的區(qū)別

    這篇文章主要介紹了java==運算符和equals()方法的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Mac系統(tǒng)上安裝?JDK?8?最穩(wěn)最全教程(Homebrew?方式)

    Mac系統(tǒng)上安裝?JDK?8?最穩(wěn)最全教程(Homebrew?方式)

    Homebrew是一個開源的包管理器,專為macOS(盡管也可以在Linux上使用)設(shè)計,用來簡化在Mac操作系統(tǒng)上安裝軟件的過程,這篇文章主要介紹了Mac系統(tǒng)上使用Homebrew方式安裝JDK8最穩(wěn)最全教程的相關(guān)資料,需要的朋友可以參考下
    2026-04-04
  • Java8新特性之lambda(動力節(jié)點Java學院整理)

    Java8新特性之lambda(動力節(jié)點Java學院整理)

    這篇文章主要介紹了Java8新特性之lambda(動力節(jié)點Java學院整理)表達式的相關(guān)知識,包括lambda語法方面的知識,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-06-06
  • Spring @RequestMapping 注解及使用技巧詳解

    Spring @RequestMapping 注解及使用技巧詳解

    @RequestMapping是Spring MVC 中定義請求映射規(guī)則的核心注解,用于將HTTP請求映射到Controller處理方法,下面給大家介紹Spring @RequestMapping 注解及使用技巧,感興趣的朋友一起看看吧
    2025-06-06
  • 全方位解讀JDK和JRE的區(qū)別及聯(lián)系

    全方位解讀JDK和JRE的區(qū)別及聯(lián)系

    這篇文章主要介紹了JDK和JRE的區(qū)別及聯(lián)系,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • Jedis操作Redis數(shù)據(jù)庫的方法

    Jedis操作Redis數(shù)據(jù)庫的方法

    這篇文章主要為大家詳細介紹了Jedis操作Redis數(shù)據(jù)庫的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • 詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化

    詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化

    本篇文章主要介紹了詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化,具有一定的參考價值,有興趣的可以了解一下
    2017-09-09
  • springboot返回前端中文亂碼的解決

    springboot返回前端中文亂碼的解決

    這篇文章主要介紹了springboot返回前端中文亂碼的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09

最新評論

错那县| 阳朔县| 阳山县| 秭归县| 翼城县| 阳东县| 隆回县| 西安市| 河津市| 左云县| 信宜市| 砚山县| 乌鲁木齐县| 临澧县| 砚山县| 罗山县| 枣阳市| 漳平市| 涿州市| 金华市| 宁乡县| 静安区| 新闻| 长子县| 盐边县| 秦皇岛市| 瑞安市| 湟中县| 普安县| 伊川县| 友谊县| 会理县| 自治县| 南召县| 昔阳县| 利津县| 庆城县| 开封市| 定边县| 太和县| 景宁|