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

Spring 依賴注入與循環(huán)依賴總結(jié)

 更新時(shí)間:2025年08月21日 11:02:37   作者:xz在努力  
這篇文章給大家介紹Spring 依賴注入與循環(huán)依賴總結(jié)篇,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

1. Spring 三級緩存解決循環(huán)依賴

? 適用場景:字段注入(@Autowired 直接加在字段上)或 Setter 注入(@Autowired 加在 Setter 方法上)。

? 解決流程

  1. 一級緩存(singletonObjects):存放完全初始化好的單例 Bean。
  2. 二級緩存(earlySingletonObjects):存放提前暴露的半成品 Bean(已實(shí)例化但未初始化)。
  3. 三級緩存(singletonFactories):存放生成 Bean 的 ObjectFactory(用于延遲創(chuàng)建代理對象)。 ?? 關(guān)鍵點(diǎn):Spring 先創(chuàng)建 Bean 的實(shí)例(調(diào)用無參構(gòu)造器),再通過緩存逐步解決依賴,避免死鎖。

舉例:

個(gè)人理解就是,以UserService為例,先創(chuàng)建UserService單例實(shí)例放在一級緩存中,如果檢測到如@Transition等注解,將單例實(shí)例包裝成工廠存到三級緩存中,到UserService初始化時(shí)發(fā)現(xiàn)自注入,分別從一二三級緩存中查找(告訴我查找什么),發(fā)現(xiàn)三級緩存中包含UserService 的工廠,然后調(diào)用改工廠生成代理對象,并且該代理對象中有對UserService為原始對象的引用,而不是對代理對象的引用,然后生成代理對象存到二級緩存中,并注入到原始對象自注入的UserService中(此時(shí)原始對象不是有對代理對象的引用嗎?),然后繼續(xù)完成初始化如@PostConstruct,然后將代理對象放到一級緩存中(此時(shí)原始對象還在嗎?),最后清楚二級三級緩存中的UserService代理對象和工廠。

你的理解基本正確,但有些細(xì)節(jié)需要澄清和補(bǔ)充。讓我們以 UserService 為例,梳理 Spring 解決循環(huán)依賴(自注入)的完整流程,并明確每一步緩存的狀態(tài)和對象引用關(guān)系。

1. 創(chuàng)建UserService原始對象

  • 動作:Spring 調(diào)用 UserService 的構(gòu)造函數(shù),創(chuàng)建一個(gè)原始對象(非代理)。
  • 緩存狀態(tài)
    • 一級緩存(單例池):無 UserService。
    • 二級緩存(早期暴露對象):無 UserService。
    • 三級緩存(對象工廠):無 UserService

2. 將原始對象包裝成工廠,存入三級緩存

  • 動作
    • 檢測到 UserService 需要代理(如被 @Transactional 標(biāo)記),Spring 將原始對象包裝成一個(gè) ObjectFactory 工廠,存入三級緩存。
    • 此時(shí)對象尚未初始化(未填充屬性、未執(zhí)行 @PostConstruct)。
  • 緩存狀態(tài)
    • 一級緩存:無 UserService。
    • 二級緩存:無 UserService
    • 三級緩存UserService 的 ObjectFactory。

3. 處理UserService的自注入

  • 動作
    • Spring 開始初始化 UserService,發(fā)現(xiàn)它依賴自身(如通過 @Autowired 自注入)。
    • 依次從一級、二級、三級緩存查找:
      1. 一級緩存:未找到(因?yàn)?nbsp;UserService 未完全初始化)。
      2. 二級緩存:未找到。
      3. 三級緩存:找到 UserService 的 ObjectFactory,調(diào)用它生成對象。
  • 生成代理對象
    • 工廠調(diào)用會創(chuàng)建 UserService 的代理對象(如 JDK 動態(tài)代理或 CGLIB 代理)。
    • 關(guān)鍵點(diǎn):代理對象內(nèi)部持有對原始對象的引用(即 target 屬性指向原始對象)。
  • 緩存更新
    • 將代理對象存入二級緩存(此時(shí)原始對象仍在創(chuàng)建中)。
    • 三級緩存中的工廠不會被移除(直到 UserService 完全初始化)。
  • 注入依賴
    • 將代理對象注入到原始對象的自依賴字段中(此時(shí)原始對象持有代理對象的引用)。

4. 繼續(xù)初始化原始對象

  • 動作
    • 完成屬性填充(如其他依賴注入)。
    • 執(zhí)行 @PostConstruct 初始化方法。
    • 此時(shí)原始對象已完全初始化,但仍是原始對象(未被代理替換)。
  • 緩存狀態(tài)
    • 一級緩存:無 UserService(因?yàn)樯形捶湃耄?/li>
    • 二級緩存UserService 的代理對象。
    • 三級緩存UserService 的 ObjectFactory。

5. 將代理對象提升到一級緩存

  • 動作
    • Spring 將二級緩存中的代理對象移動到一級緩存(單例池)。
    • 清除二級緩存和三級緩存中的 UserService 相關(guān)條目。
  • 緩存狀態(tài)
    • 一級緩存UserService 的代理對象。
    • 二級緩存:無 UserService。
    • 三級緩存:無 UserService

關(guān)鍵問題解答

  • 原始對象的去向
    • 原始對象被代理對象持有(通過 target 屬性引用),但對外暴露的永遠(yuǎn)是代理對象。
    • 原始對象不會被銷毀,它作為代理的目標(biāo)對象長期存在。
  • 自注入的引用關(guān)系
    • 原始對象中注入的是代理對象(通過三級緩存的工廠提前暴露)。
    • 代理對象內(nèi)部持有原始對象的引用(形成“代理 → 原始對象 → 代理”的引用鏈)。
  • 最終狀態(tài)
    • 一級緩存中是代理對象,原始對象僅作為代理的目標(biāo)存在。
    • 所有依賴 UserService 的 Bean 獲得的都是代理對象。

理解誤區(qū):原始對象和代理對象之間相互引用就是循環(huán)依賴,因?yàn)橐枚际俏ㄒ坏膶ο蟆?/span>

2. 無法用三級緩存解決的場景

? 構(gòu)造器循環(huán)依賴(Constructor Circular Dependency):

@Service public class A { 
    private final B b; 
    public A(B b) { 
        this.b = b; 
    } // 構(gòu)造器依賴 B 
}
@Service public class B { 
    private final A a;
    public B(A a) { 
    this.a = a; 
    } // 構(gòu)造器依賴 A 
}
  • 原因:構(gòu)造器注入必須在實(shí)例化時(shí)完成依賴注入,無法提前暴露半成品 Bean。
  • 結(jié)果:直接拋出 BeanCurrentlyInCreationException。

? 多例(Prototype)作用域的循環(huán)依賴

  • Spring 不處理多例 Bean 的循環(huán)依賴,直接報(bào)錯(cuò)。

3.@Autowired指定構(gòu)造器注入

  • 默認(rèn)行為:如果類只有一個(gè)構(gòu)造器,Spring 會自動用它注入依賴。
  • 多構(gòu)造器時(shí):需要用 @Autowired 明確指定哪個(gè)構(gòu)造器生效:
@Service 
public class UserService { 
    private final OrderService orderService; 
    @Autowired // 顯式指定帶參構(gòu)造器 
    public UserService(OrderService orderService) { 
    this.orderService = orderService; 
    } 
    public UserService() {} // 無參構(gòu)造器(默認(rèn)不生效)
}
  • 優(yōu)點(diǎn):強(qiáng)制依賴、不可變(final 字段)、易于測試。

4.@Value注入配置

  • 默認(rèn)行為:如果配置不存在,Spring 會拋出 IllegalArgumentException
  • 解決方案
    1. 設(shè)置默認(rèn)值(推薦):
@Value("${api.key:default-value}") 
private String apiKey; // 配置缺失時(shí)使用 "default-value"
  1. 允許 null
@Value("${api.key:#{null}}") 
private String apiKey; // 配置缺失時(shí)注入 nul
  1. 手動檢查(復(fù)雜場景):
private String apiKey; 
public UserService(Environment env) { 
    this.apiKey = env.getProperty("api.key", "default-value"); 
}

總結(jié)對比表

場景能否解決循環(huán)依賴推薦方案
字段/Setter 注入?(三級緩存)可選依賴、快速開發(fā)
構(gòu)造器注入?(直接報(bào)錯(cuò))強(qiáng)制依賴、核心業(yè)務(wù)邏輯
@Value 注入配置不涉及循環(huán)依賴加默認(rèn)值(${key:default}
多例 Bean 循環(huán)依賴?(直接報(bào)錯(cuò))避免多例 Bean 互相依賴

最佳實(shí)踐

  1. 優(yōu)先用構(gòu)造器注入(強(qiáng)制依賴 + 不可變性)。
  2. 循環(huán)依賴改用 Setter/字段注入 或 @Lazy。
  3. @Value 務(wù)必設(shè)置默認(rèn)值,避免因配置缺失導(dǎo)致啟動失敗。

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

相關(guān)文章

  • Java對象布局(JOL)實(shí)現(xiàn)過程解析

    Java對象布局(JOL)實(shí)現(xiàn)過程解析

    這篇文章主要介紹了Java對象布局(JOL)實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • SpringBoot返回統(tǒng)一的JSON標(biāo)準(zhǔn)格式實(shí)現(xiàn)步驟

    SpringBoot返回統(tǒng)一的JSON標(biāo)準(zhǔn)格式實(shí)現(xiàn)步驟

    這篇文章主要介紹了SpringBoot返回統(tǒng)一的JSON標(biāo)準(zhǔn)格式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • springboot配置flyway(入門級別教程)

    springboot配置flyway(入門級別教程)

    本文介紹了springboot配置flyway,主要介紹基于SpringBoot集成flyway來管理數(shù)據(jù)庫的變更,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Spring Cloud Alibaba 本地調(diào)試介紹及方案設(shè)計(jì)

    Spring Cloud Alibaba 本地調(diào)試介紹及方案設(shè)計(jì)

    為了解決 本地調(diào)試 的問題,本文實(shí)現(xiàn)了一種簡單實(shí)用的策略,可以通過 Nacos 動態(tài)配置服務(wù)路由,還可以基于用戶,部門,組織等級別配置服務(wù)路由,實(shí)現(xiàn) 本地調(diào)試 的同時(shí),實(shí)際上也實(shí)現(xiàn) 灰度發(fā)布,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • Java隱藏特性之雙括號初始化詳解

    Java隱藏特性之雙括號初始化詳解

    Java?語言擁有許多隱藏而強(qiáng)大的特性,其中之一是雙括號初始化,這篇文章將詳細(xì)介紹雙括號初始化的概念、用法和示例代碼,希望對大家有所幫助
    2023-12-12
  • Java中的這些騷操作你不能不知道!!!

    Java中的這些騷操作你不能不知道!!!

    今天在看python相關(guān)的東西,看到各種騷操作,回頭想了下Java有沒有什么騷操作,整理下面幾種,一起看一下吧,希望能給你帶來幫助
    2021-07-07
  • SpringMVC文件上傳 多文件上傳實(shí)例

    SpringMVC文件上傳 多文件上傳實(shí)例

    這篇文章主要介紹了SpringMVC文件上傳 多文件上傳實(shí)例,有需要的朋友可以參考一下
    2014-01-01
  • Java SPI 機(jī)制知識點(diǎn)總結(jié)

    Java SPI 機(jī)制知識點(diǎn)總結(jié)

    在本篇文章里小編給大家整理的是一篇關(guān)于Java SPI 機(jī)制知識點(diǎn)總結(jié)內(nèi)容,需要的朋友們可以參考下。
    2020-02-02
  • 如何使用SpringSecurity保護(hù)程序安全

    如何使用SpringSecurity保護(hù)程序安全

    這篇文章主要介紹了如何使用SpringSecurity保護(hù)程序安全,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Spring切面優(yōu)先級與基于xml的AOP實(shí)現(xiàn)方法詳解

    Spring切面優(yōu)先級與基于xml的AOP實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Spring切面的優(yōu)先級與基于xml的AOP的詳細(xì)步驟,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11

最新評論

河津市| 罗田县| 长乐市| 白河县| 教育| 深圳市| 哈尔滨市| 舟曲县| 西安市| 清涧县| 丰顺县| 江陵县| 绥滨县| 庄浪县| 宜都市| 怀宁县| 类乌齐县| 绵阳市| 宁安市| 昆山市| 长汀县| 宿迁市| 镇宁| 绥中县| 永年县| 马边| 织金县| 黑水县| 库车县| 定安县| 澄城县| 吉安市| 冀州市| 新乡市| 永济市| 平谷区| 富锦市| 西盟| 光泽县| 梅州市| 德化县|