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

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

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

是什么

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

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

兩種注入方式

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

/**
 * 通過構(gòu)造器的方式注入依賴,構(gòu)造器的方式注入依賴的bean,下面兩個(gè)bean循環(huán)依賴
 * 測(cè)試后發(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 默認(rèn)支持

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

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

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

三級(jí)緩存詳解

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

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

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

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

Bean的創(chuàng)建順序

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

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

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

總結(jié)

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

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

相關(guān)文章

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

    深入解析System.load 與 System.loadLibrary

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

    在mybatis中使用mapper進(jìn)行if條件判斷

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

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

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

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

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

    JSP request.setAttribute()詳解及實(shí)例

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

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

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

    Java中Socket下載一個(gè)文本文件

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

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

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

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

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

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

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

最新評(píng)論

安达市| 于田县| 许昌县| 穆棱市| 平原县| 商水县| 滕州市| 司法| 海宁市| 电白县| 肥西县| 西宁市| 奉节县| 万盛区| 武安市| 湘潭县| 中超| 宣威市| 元阳县| 拉萨市| 邻水| 始兴县| 崇仁县| 平邑县| 满洲里市| 略阳县| 个旧市| 澎湖县| 江西省| 东至县| 卢氏县| 金昌市| 贞丰县| 江山市| 山丹县| 高要市| 铁岭市| 定兴县| 兴国县| 留坝县| 阿克苏市|