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

Spring循環(huán)依賴實例詳解

 更新時間:2026年03月13日 09:28:57   作者:程序員碼小跳  
Spring循環(huán)依賴是指兩個或多個Bean相互依賴,形成閉環(huán),Spring通過巧妙的機制(如三級緩存)默認支持setter注入的循環(huán)依賴,但不支持constructor注入的循環(huán)依賴(會拋異常),本文介紹spring循環(huán)依賴的相關(guān)操作,感興趣的朋友跟隨小編一起看看吧

是什么

Spring循環(huán)依賴指兩個或多個 Bean 相互依賴,形成閉環(huán)。

Spring 通過巧妙的機制(如三級緩存)默認支持 setter 注入的循環(huán)依賴,但不支持 constructor 注入的循環(huán)依賴(會拋異常)。

兩種注入方式

A、構(gòu)造器注入(如 @Autowired 在 constructor 上):容易造成無法解決的循環(huán)依賴,不推薦使用【現(xiàn)象:無法new對象,因為互相是構(gòu)造函數(shù)的入?yún)?,編譯報錯】,會拋 BeanCurrentlyInCreationException。

/**
 * 通過構(gòu)造器的方式注入依賴,構(gòu)造器的方式注入依賴的bean,下面兩個bean循環(huán)依賴
 * 測試后發(fā)現(xiàn),構(gòu)造器循環(huán)依賴是無法解決的
 */
public class ClientConstructor {
    public static void main(String[] args) {
        new ServiceA(new ServiceB(new ServiceA(new ServiceB())));
    }
}

B、Setter 注入:通過 setter 方法或字段注入(如 @Autowired 在字段上),Spring 默認支持

@Component
public class A {
    @Autowired
    private B b;  // setter 注入
}
@Component
public class B {
    @Autowired
    private A a;  // setter 注入
}

循環(huán)依賴的解決辦法【重點】

重要結(jié)論:Spring 內(nèi)部通過3級緩存來解決循環(huán)依賴,核心是“提前暴露”半成品 Bean(AOP 代理前),允許其他 Bean 先引用。所謂的三級緩存其實就是 Spring 容器內(nèi)部用來解決循環(huán)依賴問題的三個 Map,這三個 Map 在 DefaultSingletonBeanRegistry 類中。

三級緩存詳解

  1. singletonObjects(一級緩存):我愿稱之為單例池,常說的 Spring 容器就是指它(因為默認的bean生命周期是singleton),我們獲取單例 bean 就是在這里面獲取的,存放已經(jīng)經(jīng)歷了完整生命周期的Bean對象【存放完全初始化的 Bean】
  2. earlySingletonObjects(二級緩存):存放早期暴露出來的Bean對象,Bean的生命周期未結(jié)束【存放已經(jīng)實例化,但屬性還未填充完整的半成品 bean】
  3. singletonFactories(三級緩存):存放可以生成Bean的工廠,用于生產(chǎn)(創(chuàng)建)對象【存放FactoryBean工廠池】

創(chuàng)建過程(以 A 依賴 B,B 依賴 A 為例)

  1. 實例化 A:Spring 調(diào)用 getBean(A),創(chuàng)建 A 實例(無屬性),放入三級緩存(singletonFactories,作為 lambda:() -> getEarlyBeanReference(A))。
  2. 注入 A 的屬性:發(fā)現(xiàn)依賴 B,調(diào)用 getBean(B)。
  3. 實例化 B:類似,創(chuàng)建 B 實例,放入三級緩存。
  4. 注入 B 的屬性:發(fā)現(xiàn)依賴 A,從三級緩存獲取 A 的工廠,生成早期 A(半成品),放入二級緩存,并注入到 B。
  5. 完成 B:B 初始化完畢,移到一級緩存。
  6. 返回到 A:A 繼續(xù)注入 B(已完成),完成初始化,移到一級緩存。
  • 如果涉及 AOP:三級緩存的工廠會生成代理對象,確保循環(huán)中代理一致。

getSingleton(): 從容器里面獲得單例的bean,沒有的話則會創(chuàng)建 bean
doCreateBean(): 執(zhí)行創(chuàng)建 bean 的操作(在 Spring 中以 do 開頭的方法都是干實事的方法)
populateBean(): 創(chuàng)建完 bean 之后,對 bean 的屬性進行填充
addSingleton(): bean 初始化完成之后,添加到單例容器池中,下次執(zhí)行 getSingleton() 方法時就能獲取到

Bean的創(chuàng)建順序

Bean的創(chuàng)建順序是由BeanDefinition的注冊順序來決定的, 當然依賴關(guān)系也會影響B(tài)ean創(chuàng)建順序,比如A依賴B,那肯定B先創(chuàng)建,A后創(chuàng)建。

那BeanDefinition的注冊順序由什么來決定的?
主要是由注解(配置)的解析順序來決定,順序如下:

  @Configuration 
  @Component 
  @Import-類
  @Bean
  @Import—ImportBeanDefinitionRegistrar

總結(jié)

  1. 調(diào)用doGetBean()方法,想要獲取beanA,于是調(diào)用getSingleton()方法從緩存中查找beanA
  2. 在getSingleton()方法中,從一級緩存中查找,沒有,返回null
  3. doGetBean()方法中獲取到的beanA為null,于是走對應的處理邏輯,調(diào)用getSingleton()的重載方法(參數(shù)為ObjectFactory的)
  4. 在getSingleton()方法中,先將beanA_name添加到一個集合中,用于標記該bean正在創(chuàng)建中。然后回調(diào)匿名內(nèi)部類的creatBean()方法
  5. 進入AbstractAutowireCapableBeanFactory#doCreateBean(),先反射調(diào)用構(gòu)造器創(chuàng)建出beanA的實例,然后判斷。是否為單例、是否允許提前暴露引用(對于單例一般為true)、是否正在創(chuàng)建中〈即是否在第四步的集合中)。判斷為true則將beanA添加到【三級緩存】中
  6. 對beanA進行屬性填充,此時檢測到beanA依賴于beanB,于是開始查找beanB
  7. 調(diào)用doGetBean()方法,和上面beanA的過程一樣,到緩存中查找beanB,沒有則創(chuàng)建,然后給beanB填充屬性
  8. 此時beanB依賴于beanA,調(diào)用getsingleton()獲取beanA,依次從一級、二級、三級緩存中找,此時從三級緩存中獲取到beanA的創(chuàng)建工廠,通過創(chuàng)建工廠獲取到singletonObject,此時這個singletonObject指向的就是上面在doCreateBean()方法中實例化的bean
  9. 這樣beanB就獲取到了beanA的依賴,于是beanB順利完成實例化,并將beanA從三級緩存移動到二級緩存中
  10. 隨后beanA繼續(xù)他的屬性填充工作,此時也獲取到了beanB,beanA也隨之完成了創(chuàng)建,回到getsingleton()方法中繼續(xù)向下執(zhí)行,將beanA從二級緩存移動到一級緩存中

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

相關(guān)文章

  • 深入解析System.load 與 System.loadLibrary

    深入解析System.load 與 System.loadLibrary

    以下是對System.load與System.loadLibrary進行了詳細的分析介紹。需要的朋友可以過來參考下
    2013-08-08
  • 在mybatis中使用mapper進行if條件判斷

    在mybatis中使用mapper進行if條件判斷

    這篇文章主要介紹了在mybatis中使用mapper進行if條件判斷,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • SpringCloud添加客戶端Eureka Client過程解析

    SpringCloud添加客戶端Eureka Client過程解析

    這篇文章主要介紹了SpringCloud添加客戶端Eureka Client過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • Spring依賴注入的三種方式小結(jié)

    Spring依賴注入的三種方式小結(jié)

    本篇文章主要介紹了Spring依賴注入的三種方式小結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • JSP request.setAttribute()詳解及實例

    JSP request.setAttribute()詳解及實例

    這篇文章主要介紹了 javascript request.setAttribute()詳解及實例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Springboot jar主清單屬性丟失解決方案

    Springboot jar主清單屬性丟失解決方案

    這篇文章主要介紹了Springboot jar主清單屬性丟失解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Java中Socket下載一個文本文件

    Java中Socket下載一個文本文件

    這篇文章主要介紹了Socket下載一個文本文件的實例代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-06-06
  • Spring Security基于過濾器實現(xiàn)圖形驗證碼功能

    Spring Security基于過濾器實現(xiàn)圖形驗證碼功能

    驗證碼就是為了防止惡意用戶采用暴力重試的攻擊手段而設(shè)置的一種防護措施,接下來在Spring Security的環(huán)境中,我們可以用兩種方案實現(xiàn)圖形驗證碼,具體實現(xiàn)方法跟隨小編一起看看吧
    2021-09-09
  • Java Swing JComboBox下拉列表框的示例代碼

    Java Swing JComboBox下拉列表框的示例代碼

    這篇文章主要介紹了Java Swing JComboBox下拉列表框的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • Spring事件監(jiān)聽機制使用和原理解析

    Spring事件監(jiān)聽機制使用和原理解析

    Spring的監(jiān)聽機制基于觀察者模式,就是就是我們所說的發(fā)布訂閱模式,這種模式可以在一定程度上實現(xiàn)代碼的解耦,本文將從原理上解析Spring事件監(jiān)聽機制,需要的朋友可以參考下
    2023-06-06

最新評論

崇阳县| 连平县| 肇州县| 安义县| 疏勒县| 河西区| 孝昌县| 盐城市| 汝城县| 浙江省| 通许县| 长兴县| 罗定市| 河北省| 沛县| 永城市| 文山县| 阜新市| 远安县| 小金县| 渝中区| 阿鲁科尔沁旗| 丹江口市| 区。| 琼结县| 通城县| 南城县| 中牟县| 上杭县| 秦皇岛市| 巴林右旗| 云霄县| 滦平县| 靖边县| 滕州市| 楚雄市| 盐城市| 布拖县| 石城县| 弥渡县| 高阳县|