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

Springboot怎么解決循環(huán)依賴(基于單例 Bean)

 更新時(shí)間:2025年05月27日 10:36:30   作者:YY-帆S  
循環(huán)依賴指兩個(gè)或多個(gè) Bean 之間相互依賴,導(dǎo)致在創(chuàng)建 Bean 的過程中出現(xiàn)“死循環(huán)”,增加了對(duì)象依賴的混亂性,依賴關(guān)系變得錯(cuò)綜復(fù)雜,下面給大家介紹Springboot怎么解決循環(huán)依賴,感興趣的朋友一起看看吧

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

循環(huán)依賴(Circular Dependency) 指兩個(gè)或多個(gè) Bean 之間相互依賴,導(dǎo)致在創(chuàng)建 Bean 的過程中出現(xiàn)“死循環(huán)”,增加了對(duì)象依賴的混亂性,依賴關(guān)系變得錯(cuò)綜復(fù)雜。

常見三種類型的循環(huán)依賴:

類型舉例Spring 是否能解決
構(gòu)造器注入循環(huán)依賴A → B → A(構(gòu)造方法注入)?
Setter / 字段注入循環(huán)依賴A → B → A(@Autowired)?
Prototype 范圍循環(huán)依賴A(原型) → B(原型) → A?

1. 構(gòu)造器注入循環(huán)依賴(Spring ?無法解決)

@Component
public class A {
    private final B b;
    @Autowired
    public A(B b) {
        this.b = b;
    }
}
@Component
public class B {
    private final A a;
    @Autowired
    public B(A a) {
        this.a = a;
    }
}

? 結(jié)果:

報(bào)錯(cuò):BeanCurrentlyInCreationException: Requested bean is currently in creation: Is there an unresolvable circular reference?

原因:Spring 必須先構(gòu)造 A 才能注入 B,但 B 的構(gòu)造又依賴 A,導(dǎo)致死循環(huán),無法通過三級(jí)緩存提前暴露 Bean

2. 字段(或 setter)注入循環(huán)依賴(Spring ?能自動(dòng)解決)

@Component
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}

? 結(jié)果:

Spring 能自動(dòng)解決,應(yīng)用成功啟動(dòng)。

  • 原因:Spring 會(huì)先構(gòu)造出一個(gè)“空的 A 實(shí)例”,將其工廠加入三級(jí)緩存,B 注入 A 時(shí)就能拿到早期引用,從而打破循環(huán)。
  • 前提:spring.main.allow-circular-references: true,必須開啟情況下才能自動(dòng)解決。然Spring 6.0 起(包括 Spring Boot 3.x)默認(rèn)為false

3. 原型作用域的循環(huán)依賴(Spring ?無法解決)

@Component
@Scope("prototype")
public class A {
    @Autowired
    private B b;
}
@Component
@Scope("prototype")
public class B {
    @Autowired
    private A a;
}

? 結(jié)果:

報(bào)錯(cuò):BeanCurrentlyInCreationException(創(chuàng)建過程中找不到可注入的 Bean)

原因:Spring 不緩存 prototype Bean 的創(chuàng)建過程,無法通過三級(jí)緩存解決依賴鏈,原型 Bean 不參與依賴管理。

二、Spring 如何解決循環(huán)依賴(基于單例 Bean)

Spring 采用一種經(jīng)典的 三級(jí)緩存機(jī)制(3-level cache) 來解決循環(huán)依賴。這個(gè)機(jī)制存在于DefaultSingletonBeanRegistry中。

?? 前提:僅對(duì) @Scope("singleton") 且使用字段或 setter 注入有效!

1. Bean 創(chuàng)建流程概覽(以 A → B → A 為例)

? Step-by-step:

創(chuàng)建 A 實(shí)例(構(gòu)造函數(shù)執(zhí)行);

A被標(biāo)記為“正在創(chuàng)建”,并將一個(gè)工廠(ObjectFactory)放入三級(jí)緩存

A 依賴 B → Spring 創(chuàng)建 B;

B 構(gòu)造完成,發(fā)現(xiàn)依賴 A → 嘗試獲取 A;

Spring 發(fā)現(xiàn) A 正在創(chuàng)建 → 從三級(jí)緩存拿到 ObjectFactory 生成早期 A 對(duì)象 → 放入二級(jí)緩存

B 成功注入 A,初始化完成;

回到 A,完成初始化。

整個(gè)過程中 Spring 使用緩存提前暴露未完成的 A 實(shí)例,從而打破了循環(huán)。

2. 三級(jí)緩存詳解

緩存層級(jí)名稱描述作用
一級(jí)緩存singletonObjects完全初始化完成的 Bean最終返回 Bean 實(shí)例
二級(jí)緩存earlySingletonObjects早期曝光的 Bean 實(shí)例用于依賴注入
三級(jí)緩存singletonFactories創(chuàng)建早期 Bean 的工廠延遲暴露 Bean 引用,支持代理等

Spring 將 Bean 提前曝光的流程:

singletonFactories -> earlySingletonObjects -> singletonObjects

3. 核心方法說明(來自源碼)

在 Spring 源碼中,關(guān)鍵方法如下:

// DefaultSingletonBeanRegistry.java
// 一級(jí)緩存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
// 二級(jí)緩存
private final Map<String, Object> earlySingletonObjects = new HashMap<>();
// 三級(jí)緩存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
  • 在創(chuàng)建 Bean 前:Spring 把一個(gè)生成 Bean 的工廠方法放入三級(jí)緩存。
  • 在注入依賴時(shí):發(fā)現(xiàn)依賴的是一個(gè)“正在創(chuàng)建”的 Bean,就會(huì)去三級(jí)緩存中拿工廠生產(chǎn)早期對(duì)象。
  • 最后再完成依賴注入,放入一級(jí)緩存,清除早期引用。

三、業(yè)務(wù)開發(fā)者解決循環(huán)依賴的方法

1、使用@Lazy懶加載依賴

使用`@Lazy`注解延遲注入依賴屬性。

@Component
public class A {
    @Autowired
    @Lazy
    private B b;
}

2、將依賴的代碼移入新類,打破依賴閉環(huán)。

A → MiddleService → B

3、在方法中動(dòng)態(tài)調(diào)用spring容器的getBean方法獲取依賴,達(dá)到延遲獲取bean,避免類中直接注入循環(huán)依賴的bean

使用 ObjectFactory 或 ApplicationContext.getBean() 延遲獲取 Bean

@Component
@Scope("prototype")
public class A {
    @Autowired
    private ObjectFactory<B> bFactory;
    public void use() {
        B b = bFactory.getObject(); // 延遲獲取
    }
}

4、改為 setter 或字段注入(避免構(gòu)造器注入)

構(gòu)造器注入是“強(qiáng)依賴”,無法提前暴露:

@Component
public class A {
    private B b;
    @Autowired
    public void setB(B b) {
        this.b = b;
    }
}

5、使用@PostConstruct 或 工廠方法延遲注入

將依賴注入放到初始化之后:

@Component
public class A {
    private final B b;
    public A(B b) {
        this.b = b;
    }
    @PostConstruct
    public void init() {
        // 在這里安全使用 b
    }
}

6、開啟Spring Boot循環(huán)依賴(不推薦,除非必要)。

spring:
    main:
        allow-circular-references: true

到此這篇關(guān)于Springboot怎么解決循環(huán)依賴(基于單例 Bean)的文章就介紹到這了,更多相關(guān)Springboot循環(huán)依賴內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用hutool工具進(jìn)行導(dǎo)入導(dǎo)出excel表格

    使用hutool工具進(jìn)行導(dǎo)入導(dǎo)出excel表格

    如何在后臺(tái)添加導(dǎo)入導(dǎo)出表格的功能呢,本期的文章將會(huì)帶領(lǐng)小伙伴們一起實(shí)現(xiàn)此功能,文中有詳細(xì)的代碼示例和圖文介紹,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-10-10
  • Spring中@Configuration注解和@Component注解的區(qū)別詳解

    Spring中@Configuration注解和@Component注解的區(qū)別詳解

    這篇文章主要介紹了Spring中@Configuration注解和@Component注解的區(qū)別詳解,@Configuration 和 @Component 到底有何區(qū)別呢?我先通過如下一個(gè)案例,在不分析源碼的情況下,小伙伴們先來直觀感受一下這兩個(gè)之間的區(qū)別,需要的朋友可以參考下
    2023-09-09
  • Java之循環(huán)結(jié)構(gòu)、break、continue用法及說明

    Java之循環(huán)結(jié)構(gòu)、break、continue用法及說明

    本文介紹了Java中的三種循環(huán)語句:while、for和do-while,并詳細(xì)講解了它們的使用方法和應(yīng)用場(chǎng)景,通過實(shí)例練習(xí),讀者可以掌握循環(huán)語句的編寫技巧
    2025-10-10
  • Mybatis中通用Mapper的InsertList()用法

    Mybatis中通用Mapper的InsertList()用法

    文章介紹了通用Mapper中的insertList()方法在批量新增時(shí)的使用方式,包括自增ID和自定義ID的情況,對(duì)于自增ID,使用tk.mybatis.mapper.additional.insert.InsertListMapper包下的insertList()方法;對(duì)于自定義ID,需要重寫insertList()方法
    2025-02-02
  • Java微信退款開發(fā)

    Java微信退款開發(fā)

    這篇文章主要為大家詳細(xì)介紹了Java微信退款開發(fā)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Java中Date數(shù)據(jù)類型的數(shù)值轉(zhuǎn)換方式

    Java中Date數(shù)據(jù)類型的數(shù)值轉(zhuǎn)換方式

    這篇文章主要介紹了Java中Date數(shù)據(jù)類型的數(shù)值轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • java &與&&的區(qū)別及實(shí)例

    java &與&&的區(qū)別及實(shí)例

    這篇文章主要介紹了java &與&&的區(qū)別的相關(guān)資料,并附簡(jiǎn)單實(shí)例,幫助大家學(xué)習(xí)理解這部分知識(shí),需要的朋友可以參考下
    2016-10-10
  • Spring中@Configuration和@Component注解的區(qū)別及原理

    Spring中@Configuration和@Component注解的區(qū)別及原理

    這篇文章主要介紹了Spring中@Configuration和@Component注解的區(qū)別及原理,從功能上來講,這些注解所負(fù)責(zé)的功能的確不相同,但是從本質(zhì)上來講,Spring內(nèi)部都將其作為配置注解進(jìn)行處理,需要的朋友可以參考下
    2023-11-11
  • idea 打包的jar運(yùn)行報(bào)

    idea 打包的jar運(yùn)行報(bào) "XXX中沒有主清單屬性"

    這篇文章主要介紹了idea 打包的jar運(yùn)行報(bào) "XXX中沒有主清單屬性",文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • java dom4j解析xml文件代碼實(shí)例分享

    java dom4j解析xml文件代碼實(shí)例分享

    這篇文章主要介紹了java dom4j解析xml文件的方法,分享給大家參考
    2013-12-12

最新評(píng)論

伊通| 仁寿县| 蓝田县| 湖北省| 田阳县| 西和县| 涞源县| 宜兴市| 望奎县| 安平县| 炎陵县| 平度市| 巩留县| 金华市| 长阳| 漠河县| 东港市| 新乐市| 农安县| 洛阳市| 望谟县| 华蓥市| 伊宁县| 湟中县| 塔河县| 舟山市| 四子王旗| 绥中县| SHOW| 中超| 定边县| 阳新县| 陵水| 黄浦区| 布尔津县| 斗六市| 泰宁县| 留坝县| 滨州市| 芦山县| 静宁县|