【一文看懂Spring循環依賴】Spring循環依賴:從陷阱破局到架構涅槃

🌪? Spring Boot循環依賴:從陷阱破局到架構涅槃

循環依賴如同莫比烏斯環上的螞蟻,看似前進卻永遠困在閉環中。本文將帶你拆解Spring中這一經典難題,從臨時救火到根治重構,構建無懈可擊的依賴體系。


🔥 一、致命閉環:當依賴鏈開始打結

📍 1. 循環依賴的三種形態
  • 構造器死鎖(無解型)

    @Service
    public class OrderService {private final UserService userService;public OrderService(UserService userService) { // 啟動即崩潰this.userService = userService; }
    }@Service
    public class UserService {private final OrderService orderService;public UserService(OrderService orderService) { // 相互等待初始化this.orderService = orderService; }
    }
    

    致命點:Spring無法通過三級緩存提前暴露Bean,直接拋出BeanCurrentlyInCreationException

  • 字段/Setter依賴(可救型)
    通過三級緩存機制可解:

    實例化OrderService
    暴露早期引用到三級緩存
    注入UserService時實例化UserService
    UserService從緩存拿到OrderService早期引用
    UserService初始化完成
    OrderService注入完整UserService
  • 異步方法閉環(隱蔽型)
    @Async@Transactional生成的代理對象會干擾依賴注入流程,導致看似無循環的代碼在運行時崩潰


🛠? 二、破局五式:從應急到根治

🧪 1. 急救方案:@Lazy的妙用與陷阱
@Service
public class OrderService {@Lazy  // 延遲注入關鍵注解@Autowired  private PaymentService paymentService; 
}

原理:生成代理對象占位,首次調用時初始化真實Bean,打破初始化死鎖
風險警示

  • 過度使用導致代理對象泛濫,調用鏈復雜度指數級增長
  • 與構造器注入結合可能引發NPE(代理對象未被觸發初始化)
?? 2. 依賴注入改造:Setter vs 構造器

Setter注入救場

@Service
public class OrderService {private PaymentService paymentService;@Autowired  // 避免構造器死鎖public void setPaymentService(PaymentService ps) {this.paymentService = ps;}
}

本質差異:構造器注入要求依賴項在實例化時完備,Setter注入允許先創建空殼再填充

🧱 3. 架構重構:三大根治術

① 抽離公共層(依賴倒置)

public interface PaymentProcessor { // 抽象接口void processPayment();
}@Service 
public class AlipayProcessor implements PaymentProcessor {...} // 實現1@Service 
public class WechatProcessor implements PaymentProcessor {...} // 實現2@Service
public class OrderService {private final PaymentProcessor processor; // 依賴抽象public OrderService(PaymentProcessor processor) {...} 
}

優勢:符合SOLID原則,徹底切斷雙向依賴

② 事件驅動(終極解耦)

@Service
public class OrderService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void createOrder() {eventPublisher.publishEvent(new OrderCreatedEvent(this)); // 發布事件}
}@Service
public class InventoryService {@EventListener // 監聽解耦public void reduceStock(OrderCreatedEvent event) {...} 
}

效果:訂單服務與庫存服務零直接依賴,通過事件總線通信

③ 門面模式(統一入口)

@Service
public class OrderFacade { // 門面服務@Autowired private OrderService orderService;@Autowired private PaymentService paymentService;public void executeOrder() {orderService.create();paymentService.charge();}
}

適用場景:多服務強關聯但需避免循環調用


?? 三、避坑指南:那些雪上加霜的操作

  1. 配置允許循環依賴(飲鴆止渴)

    spring.main.allow-circular-references=true # Spring Boot 2.6+前有效
    

    后果:高版本默認禁用此配置,且掩蓋設計缺陷

  2. 原型Bean(Prototype)的循環依賴
    每次請求創建新實例,三級緩存失效,必須用@Lazy或重構

  3. @PostConstruct中的隱式循環

    @Service
    public class ServiceA {@Autowired ServiceB serviceB;@PostConstructpublic void init() { serviceB.register(this); // 觸發ServiceB反向調用}
    }
    

    解決方案:改用ApplicationListener或事件驅動


🏆 四、最佳實踐:讓循環依賴無處遁形

  1. 防御性編碼

    • 強制構造器注入:啟動時暴露問題 > 運行時崩潰
    • 分層架構守護
      // ArchUnit檢測循環依賴
      @ArchTest
      static final ArchRule no_cycles = slices().matching("com.yourapp.(*)..").should().beFreeOfCycles();
      
  2. 依賴可視化監控

    # 生成Bean依賴圖
    curl http://localhost:8080/actuator/beans | jq '.contexts.context.beans'
    

    結合Spring Boot Actuator實時分析依賴鏈路


💎 結語:依賴的本質是契約

循環依賴的終極解決方案不在技術層面,而在架構認知。當我們用“服務能力”替代“服務調用”的視角設計系統時,模塊間將自然形成單向流動的依賴河床。正如領域驅動設計中限界上下文(Bounded Context)的隔離藝術——每個上下文都是自治的王國,通過防腐層進行優雅的外交對話。

思考題:在微服務架構中,循環依賴會以怎樣的形式存在?歡迎分享你的實戰案例。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/83270.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/83270.shtml
英文地址,請注明出處:http://en.pswp.cn/web/83270.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

el-table封裝自動滾動表格(適用大屏)

表格功能&#xff1a;自動滾動&#xff0c;鼠標移入停止滾動&#xff0c;移出繼續滾動。如果想加觸底加載新數據可以判斷 scrollWrap.scrollTop和maxScrollTop大小來加載數據&#xff0c;另寫邏輯。 <template><el-table ref"eltable" :data"tableDa…

Eureka REST 相關接口

可供非 Java 應用程序使用的 Eureka REST 操作。 appID 是應用程序的名稱&#xff0c;instanceID 是與實例關聯的唯一標識符。在 AWS 云中&#xff0c;instanceID 是實例的實例 ID&#xff1b;在其他數據中心&#xff0c;它是實例的主機名。 對于 XML/JSON&#xff0c;HTTP 的…

DSP——時鐘樹講解

配置任何外設的第一步都要看一下時鐘樹,下圖是DSP28377的時鐘樹: 由圖所示DSP28377由4個時鐘源,分別是INTOSC1、INTOSC2、XTAL、AUXCL INTOSC1:0M內部系統時鐘,備用時鐘,檢測到系統時鐘缺失自動連接到備用時鐘,也作為看門狗時鐘使用; INTOSC2:10M內部系統時鐘,復位…

少量數據達到更好效果

九坤團隊新作&#xff01;一條數據訓練AI超越上萬條數據 一 僅需一條無標簽數據和10步優化 九坤團隊訓練了13,440個大模型&#xff0c;發現熵最小化 (EM) 僅需一條無標簽數據和10步優化&#xff0c;就能實現與強化學習中使用成千上萬條數據和精心設計的獎勵機制所取得的性能提…

html - <mark>標簽

<mark> 標簽在HTML中用于高亮顯示文本&#xff0c;通常用于突出顯示某些重要的部分。它的默認樣式通常是背景色為黃色&#xff0c;但你可以通過CSS自定義其外觀。 1. 基本用法 <mark> 標簽用于標記文本的高亮顯示。它常用于搜索結果中&#xff0c;突出顯示匹配的…

YOLOv8+ByteTrack:高精度人車過線統計系統搭建指南

文章目錄 1. 引言2. YOLOv8簡介3. 過線統計原理4. 代碼實現4.1 環境準備4.2 基礎檢測代碼4.3 過線統計實現4.4 完整代碼示例5. 性能優化與改進5.1 多線程處理5.2 區域檢測優化5.3 使用ByteTrack改進跟蹤6. 實際應用中的挑戰與解決方案7. 總結與展望1. 引言 目標檢測是計算機視…

20、React常用API和Hook索引

這一小節中只給出一些API和Hook的索引&#xff0c;需要用到的時候可以去官網查詢&#xff0c;如無必要此處不列出詳細用法。React v1.19.1。 對Components的支持 以下是開發時通用的一些功能組件 APIdescription<Fragment>通常使用 <>…</> 代替&#xff0…

Python爬蟲實戰:研究feedparser庫相關技術

1. 引言 1.1 研究背景與意義 在當今信息爆炸的時代,互聯網上存在著海量的信息資源。RSS(Really Simple Syndication)作為一種標準化的信息聚合技術,被廣泛用于網站內容的發布和訂閱。通過 RSS,用戶可以方便地獲取網站更新的內容,而無需頻繁訪問各個網站。 然而,互聯網…

HTML實現的2048游戲

以下是一個純HTML實現的2048游戲代碼&#xff0c;包含CSS和JavaScript&#xff1a; <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>2048 Game</title><style>body {font-family: Arial, sans-serif;text-a…

使用Python 構建支持主流大模型與 Ollama 的統一接口平臺

?? 背景概述 近年來,隨著大語言模型(LLM)的蓬勃發展,OpenAI 的 GPT 系列、Google 的 Gemini、Anthropic 的 Claude、以及開源的 Ollama 本地模型等,逐漸成為自然語言處理、智能問答、AI 助手等應用的基礎組件。 開發者在使用這些模型時常面臨如下問題: 各模型接口不統…

計算機系統概述(4)

計算機系統層次結構&#xff1a;硬件層、系統層、應用層。 計算機的基本硬件系統由運算器、控制器、存儲器、輸入設備和輸出設備5大部件組成。 運算器、控制器等部件被集成在一起統稱為中央處理單元CPU。 存儲器是計算機系統中的記憶設備&#xff0c;分為內部存儲器和外部存…

Linux 下的COW機制(copy-on-write)

Linux通過MMU進行虛擬地址到物理地址的轉換&#xff0c;當進程執行fork()后&#xff0c;會把頁中的權限設置為RD-ONLY&#xff08;只讀&#xff09;。 MMU&#xff08;內存管理單元&#xff09; MMU本質是一個集成在CPU核心的硬件電路模塊&#xff0c;其核心任務是實現…

客戶案例 | 短視頻點播企業海外視頻加速與成本優化:MediaPackage+Cloudfront 技術重構實踐

01技術背景與業務挑戰 某短視頻點播企業深耕國內用戶市場&#xff0c;但其后臺應用系統部署于東南亞印尼 IDC 機房。 隨著業務規模擴大&#xff0c;傳統架構已較難滿足當前企業發展的需求&#xff0c;企業面臨著三重挑戰&#xff1a; ① 業務&#xff1a;國內用戶訪問海外服…

開發Vue.js組件的二三事

Vue.js作為一款漸進式JavaScript框架&#xff0c;其組件化開發模式是其核心優勢之一。在多年的Vue開發實踐中&#xff0c;我積累了一些組件開發的經驗和思考&#xff0c;在此與大家分享。 組件設計原則 單一職責原則 每個組件應該只關注一個特定的功能或UI部分。如果一個組件…

實現多路視頻截圖預覽之后上傳到后臺系統

********************父組件********************** <div class"camera-box" v-loading"i.loading"> <div class"camera-box-inner" v-for"(x, y) in i.children" :key"y children x.featureCode" v-show"…

分布式鎖-Redisson實現

目錄 本地鎖的局限性 Redisson解決分布式鎖問題 在分布式環境下&#xff0c;分布式鎖可以保證在多個節點上的并發操作時數據的一致性和互斥性。分布式鎖有多種實現方案&#xff0c;最常用的兩種方案是&#xff1a;zookeeper和redis&#xff0c;本文介紹redis實現分布式鎖方案…

【辦公類-48-04】202506每月電子屏臺賬匯總成docx-5(問卷星下載5月范圍內容,自動獲取excel文件名,并轉移處理)

背景需求&#xff1a; 1-4月電子屏表格&#xff0c;都是用這個代碼將EXCEL數據整理成分類成3個WORD表格。 【辦公類-48-04】20250118每月電子屏臺賬匯總成docx-4&#xff08;提取EXCLE里面1月份的內容&#xff0c;自制月份文件夾&#xff09;-CSDN博客文章瀏覽閱讀1.2k次&…

【websocket】安裝與使用

websocket安裝與使用 1. 介紹2. 安裝3. websocketpp常用接口4. Websocketpp使用4.1 服務端4.2 客戶端 1. 介紹 WebSocket 是從 HTML5 開始支持的一種網頁端和服務端保持長連接的 消息推送機制。 傳統的 web 程序都是屬于 “一問一答” 的形式&#xff0c;即客戶端給服務器發送…

微算法科技(NASDAQ:MLGO)基于信任的集成共識和灰狼優化(GWO)算法,搭建高信任水平的區塊鏈網絡

隨著數字化轉型的加速&#xff0c;區塊鏈技術作為去中心化、透明且不可篡改的數據存儲與交換平臺&#xff0c;正逐步滲透到金融、供應鏈管理、物聯網等多個領域&#xff0c;探索基于信任的集成共識機制&#xff0c;并結合先進的優化算法來提升區塊鏈網絡的信任水平&#xff0c;…

【項目實戰】通過多模態+LangGraph實現PPT生成助手

PPT自動生成系統 基于LangGraph的PPT自動生成系統&#xff0c;可以將Markdown文檔自動轉換為PPT演示文稿。 功能特點 Markdown解析&#xff1a;自動解析Markdown文檔結構PPT模板分析&#xff1a;分析PPT模板的布局和風格智能布局決策&#xff1a;匹配內容與合適的PPT布局自動…