国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

從源碼層面深度剖析Spring循環依賴

OSC開源社區 ? 來源:OSCHINA 社區 ? 2022-12-22 10:34 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群


以下舉例皆針對單例模式討論圖解參考:https://www.processon.com/view/link/60e3b0ae0e3e74200e2478ce?

1、Spring 如何創建 Bean?

對于單例 Bean 來說,在 Spring 容器整個生命周期內,有且只有一個對象。Spring 在創建 Bean 過程中,使用到了三級緩存,即 DefaultSingletonBeanRegistry.java 中定義的:
    /** Cache of singleton objects: bean name to bean instance. */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name to ObjectFactory. */
    private final Map<String, ObjectFactory> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name to bean instance. */
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

以 com.gyh.general 包下的 OneBean 為例,debug springboot 啟動過程,分析 spring 是如何創建 bean 的。

參考圖中spring 創建 bean的過程。其中最關鍵的幾步有:1.getSingleton(beanName, true)依次從一二三級緩存中查找 bean 對象,如果緩存中存在對象,則直接返回 (early);2.createBeanInstance(beanName, mbd, args)選一個合適的構造函數,new 實例對象 (instance),此時的 instance 中依賴的屬性還都是 null,屬于半成品;3.singletonFactories.put(beanName, oneSingletonFactory)利用上一步的 instance,構建一個 singletonFactory,并將其放到三級緩存中;4.populateBean(beanName, mbd, instanceWrapper)填充 bean:為該 bean 定義的屬性創建對象或賦值;5.initializeBean("one",oneInstance, mbd)初始化 bean:對 bean 進行初始化或其他加工,如生成代理對象 (proxy);6.getSingleton(beanName, false)依次在一二級緩存中查找,檢查是否有因循環依賴導致提前生成的對象,有的話與初始化后的對象是否一致;

2、Spring 如何解決循環依賴?

以 com.gyh.circular.threeCache 包下的 OneBean 和 TwoBean 為例 ,兩個 Bean 相互依賴(即形成閉環)。參考圖中spring 解決循環依賴的過程可知,spring 利用三級緩中的 objectFactory 生成并返回一個 early 對象,提前暴露這個 early 地址,供其他對象依賴注入使用,以此解決循環依賴問題。

3、Spring 不能解決哪些循環依賴?

3.1 循環中使用了@Async注解

3.1.1 為什么循環中使用了@Async 會報錯?

以 com.gyh.circular.async 包下的 OneBean 和 TwoBean 為例,兩個 bean 相互依賴,且 oneBean 中的方法使用了@Async 注解,此時啟動 spring 失敗,報錯信息為:org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a.one': Bean with name 'a.one' has been injected into other beans [a.two] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.并通過 debug 代碼,發現報錯位置在 AbstractAutowireCapableBeanFactory#doCreateBean 方法內,由于 earlySingletonReference != null 且 exposedObject != bean,導致報錯。5a2ee708-813f-11ed-8abf-dac502259ad0.png結合流程圖中spring 解決循環依賴及上述圖片中可知:1.行 1 中 bean 為 createBeanInstance 創建的實例 (address1)2.行 2 中 exposedObject 為 initializeBean 后生成的代理對象 (address2)3.行 3 中 earlySingletonReference 為 getEarlyBeanReference 時創建的對象【此處地址同 bean (address1)】深層原因為:先前 TwoBean 在 populateBean 時已經依賴了地址為 address1 的 earlySingletonReference 對象,而此時 OneBean 經過 initializeBean 之后,返回了地址為 address2 的新對象,導致 spring 不知道哪個才是最終版的 bean,所以報錯。earlySingletonReference 是如何生成的,參考 getSingleton ("one", true) 過程。

3.1.2 循環中使用了@Async 一定會報錯嗎?

依然以 com.gyh.circular.async 包下的 OneBean 和 TwoBean 為例,兩個 bean 相互依賴,使 TwoBean (非 OneBean) 中的方法使用了@Async 注解,此時啟動 spring 成功,并未報錯。debug 代碼可知:雖然 TwoBean 使用了 @Async 注解,但其 earlySingletonReference = null; 故不會引起報錯。5a6698f6-813f-11ed-8abf-dac502259ad0.png深層原因為:OneBean 先被創建,TwoBean 后創建,再整條鏈路中,并未在三級緩存中查找過 TwoBean 的 objectFactory 。(OneBean 在創建過程中,被找過兩次,即 one-> two ->one;TwoBean 的創建過程中,只找過它一次,即 two ->one。)由此可得:@Async 造成循環依賴報錯的先約條件為:1.循環依賴中的 Bean 使用了 @Async 注解2.且這個 Bean,比循環內其他 Bean 先創建。3.注:一個 Bean 可能會同時存在于多個循環內;只要存在它是某個循環內第一個被創建的 Bean,那么就會報錯。

3.1.3 為什么循環中使用了 @Transactional 不會報錯?

已知使用了 @Transactional 注解的 Bean,Spring 也會為其生成代理對象,但為什么這種 Bean 在循環里時不會產生報錯呢?以 com.gyh.circular.transactional 包下的 OneBean 和 TwoBean 為例,兩個 Bean 相互依賴,且 OneBean 中的方法使用了 @Transactional 注解,啟動 Spring 成功,并不會報錯。debug 代碼可知,生成 OneBean 過程中,雖然 earlySingletonReference != null,但 initializeBean 之后的 exposedObject 和 原始實例的地址相同(即 initializeBean 步驟中,并未對實例生成代理),所以不會產生報錯。5ad3f7c0-813f-11ed-8abf-dac502259ad0.png3.1.4 為什么同樣是代理會產生兩種不同的現象?同樣是生成代理對象,同樣是參與到循環依賴中,會產生不同現象的原因是:當他們處在循環依賴中時,生成代理的節點不同:1.@Transactional 在 getEarlyBeanReference 時生成代理,提前暴露出代理之后的地址(即最終地址);2.@Async 在 initializeBean 時生成代理,導致提前暴露出去的地址不是最終地址,造成報錯。為什么 @Async 不能在 getEarlyBeanReference 時生成代理呢?對比下兩者執行的代碼過程發現:兩者都是在 AbstractAutoProxyCreator#getEarlyBeanReference 的方法對原始實例對象進行包裝,如下圖5afa0d48-813f-11ed-8abf-dac502259ad0.png使用 @Transactional 的 Bean 在 create proxy 時,獲取到一個 advice ,隨即生成了代理對象 proxy.?5b3be77c-813f-11ed-8abf-dac502259ad0.png而使用 @Async 的 Bean 在 create proxy 時,沒有獲取到 advice,不能被代理.5b6c1d7a-813f-11ed-8abf-dac502259ad0.png

3.1.5 為什么 @Async 在 getEarlyBeanReference 時不能返回一個 advice?

在 AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean 方法內,其主要做的事情有:1.找到當前 spring 容器中所有的 Advisor2.返回適配當前 bean 的所有 Advisor第一步返回的 Advisor 有 BeanFactoryCacheOperationSourceAdvisor 和 BeanFactoryTransactionAttributeSourceAdvisor,并無處理 Async 相關的 Advisor.刨根問底,追查為什么第一步不會返回處理 Async 相關的 Advisor?已知使用 @Async @Transactional @Cacheable 需要提前進行開啟,即提前標注 @EnableAsync、@EnableTransactionManagement、@EnableCaching 。以 @EnableTransactionManagement、@EnableCaching 為例,在其注解定義中,引入了 Selector 類,Selector 中又引入了 Configuration 類,在 Configuration 類中,創建了對應 Advisor 并放到了 spring 容器中,所以第一步才能得到這兩個 Advisor.而 @EnableAsync 的定義中引入的 Configuration 類,創建的是 AsyncAnnotationBeanPostProcessor 并非一個 Advisor,所以第一步不會得到它,所以 @Async 的 bean 不會在這一步被代理。

3.2 構造函數引起的循環依賴

以 com.gyh.circular.constructor 包下的 OneBean 和 TwoBean 為例,兩個類的構造函數中各自依賴對方,啟動 spring,報錯:org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'c.one': Requested bean is currently in creation: Is there an unresolvable circular reference?debug 代碼可知,兩個 bean 在根據構造函數 new instance 時,就已經陷入的死循環,無法提前暴露可用的地址,所以只能報錯。

4、如何解決以上循環依賴報錯?

1.不用 @Async,將需要異步操作的方法,放到線程池中執行。(推薦)2.提出 @Async 標注的方法。(推薦)3.將使用 @Async 的方法提出到單獨的類中,該類只做異步處理,不做其他業務依賴,即避免形成循環依賴,從而解決報錯問題。參考 com.gyh.circular.async.extract 包。4.盡量不使用構造函數依賴對象。(推薦)5.破壞循環(不推薦)即不形成閉環,在開發之前,規劃好對象依賴,方法調用鏈,盡量做到不使用循環依賴。(較難,隨著迭代開發不斷變化,很可能產生循環)6.破壞創建順序(不推薦)7.由于使用 @Async 注解的所在類,比循環依賴內其他類先創建時才會報錯,那么想辦法使該類不先于其他類先創建,也可解決該問題,如:@DependsOn、@Lazy

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 源碼
    +關注

    關注

    8

    文章

    685

    瀏覽量

    31317
  • spring
    +關注

    關注

    0

    文章

    341

    瀏覽量

    15935

原文標題:從源碼層面深度剖析 Spring 循環依賴

文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    車規藍牙模塊技術深度剖析

    在汽車電子化迅猛發展的當下, 車規藍牙模塊 ——這一集成藍牙功能的PCBA(印刷電路板組裝件),已成為推動汽車智能化、網聯化的核心力量。本文將從技術層面深入剖析車規藍牙模塊的應用、性能指標、安全性
    的頭像 發表于 03-04 14:04 ?728次閱讀

    CAN協議的深度剖析

    單元(ECU)之間的高效通信問題。本文將從技術原理、幀結構、錯誤處理機制、應用場景及未來發展趨勢等方面,對CAN協議進行深度剖析
    的頭像 發表于 03-03 17:08 ?451次閱讀
    CAN協議的<b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    OPC UA協議深度剖析

    。本文將從協議架構、核心技術、應用場景及未來發展趨勢等維度進行全面剖析,幫助讀者深入理解這一工業通信領域的核心標準。
    的頭像 發表于 03-03 17:00 ?456次閱讀

    串口協議的深度剖析

    串口通信協議作為電子設備間數據交互的基礎技術,自20世紀60年代誕生以來,始終在工業控制、嵌入式系統和物聯網等領域扮演著核心角色。本文將從技術原理、協議架構、應用場景及未來演進四個維度,對串口協議展開深度剖析
    的頭像 發表于 03-02 17:32 ?1019次閱讀

    深度剖析TL431與TL432:特性到應用的全方位指南

    深度剖析TL431與TL432:特性到應用的全方位指南 在電子工程師的日常設計工作中,電壓參考器件是不可或缺的組成部分。TI的TL431和TL432作為經典的精密可編程參考器件,憑借其出色的性能
    的頭像 發表于 03-02 15:25 ?87次閱讀

    德州儀器PCM1789-Q1音頻DAC深度剖析特性到應用

    德州儀器PCM1789-Q1音頻DAC深度剖析特性到應用 在音頻領域,一款高性能的數字-to-模擬轉換器(DAC)對于音質的提升起著至關重要的作用。今天,我們就來深入了解一下德州儀器(Texas
    的頭像 發表于 01-30 15:40 ?149次閱讀

    深度剖析LT1368運放:特性、應用與設計要點

    深度剖析 LT1366/LT1367/LT1368/LT1369 系列運放:特性、應用與設計要點 引言 在電子工程師的日常設計工作中,運算放大器是不可或缺的基本元件之一。而 Linear
    的頭像 發表于 01-29 16:45 ?215次閱讀

    可重觸發單穩態多諧振蕩器:原理到應用的深度剖析

    可重觸發單穩態多諧振蕩器:原理到應用的深度剖析 在電子電路設計領域,可重觸發單穩態多諧振蕩器是一種非常實用的電路元件,它能夠在特定的觸發條件下產生精確的脈沖信號,廣泛應用于脈沖整形、定時、延時等
    的頭像 發表于 01-27 14:20 ?191次閱讀

    高速利器:AD8465 LVDS 比較器深度剖析

    高速利器:AD8465 LVDS 比較器深度剖析 在現代高速電子系統的設計中,比較器作為關鍵組件,其性能直接決定了系統的穩定性與響應速度。今天,我將為大家深入剖析Analog Devices
    的頭像 發表于 01-07 10:00 ?176次閱讀

    PCA9546A:低電壓4通道I2C和SMBus開關的深度剖析

    PCA9546A:低電壓4通道I2C和SMBus開關的深度剖析 在電子設計領域,I2C總線的應用極為廣泛,而PCA9546A作為一款低電壓4通道I2C和SMBus開關,以其獨特的功能和特性,為工程師
    的頭像 發表于 12-29 09:30 ?324次閱讀

    TLE989x EvalBoard with TQFP/LQFP spring socket v01_1 評估板深度解析

    TLE989x EvalBoard with TQFP/LQFP spring socket v01_1 評估板深度解析 在電子設計領域,評估板是我們探索和驗證新器件性能的重要工具。今天,我們就來
    的頭像 發表于 12-20 10:40 ?1383次閱讀

    一款基于Java+Spring Boot+Vue的智慧隨訪管理系統源碼

    智慧隨訪管理系統源碼,一款基于Java+Spring Boot+Vue的B/S架構醫院隨訪管理系統源碼,采用前后端分離技術(Ant-Design+MySQL5),具有自主版權和落地案例。 隨訪管理
    的頭像 發表于 11-13 15:38 ?395次閱讀
    一款基于Java+<b class='flag-5'>Spring</b> Boot+Vue的智慧隨訪管理系統<b class='flag-5'>源碼</b>

    設計到部署:AI即服務平臺開發深度剖析

    頂層設計到最終部署,一個成功的AI即服務平臺開發是一項復雜的系統工程,它融合了軟件工程、數據科學和運維技術的精髓。
    的頭像 發表于 11-13 14:16 ?348次閱讀

    力芯微高壓LDO系列技術深度剖析電路架構到場景適配邏輯

    力芯微高壓LDO系列技術深度剖析 ,能覆蓋多場景需求,關鍵在于突破“寬壓適配-低功耗平衡-噪聲抑制”技術矛盾, 電路架構到場景適配邏輯 如下: 寬輸入電壓的實現:高壓耐受性設計? ET5H7XX
    的頭像 發表于 09-22 14:05 ?573次閱讀

    接口到架構:工控一體機定制化的深度技術剖析

    在工業4.0與數字化轉型的浪潮中,工控一體機作為工業自動化與信息化融合的核心載體,正通過深度定制化技術重構工業控制系統的底層邏輯。硬件接口的靈活配置到系統架構的模塊化設計,定制化已成為解決復雜
    的頭像 發表于 06-17 16:47 ?564次閱讀