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

spring解決循環(huán)依賴

 更新時(shí)間:2020年09月29日 14:21:19   作者:TomCoding  
這篇文章主要介紹了spring如何解決循環(huán)依賴,幫助大家更好的理解和使用spring框架,感興趣的朋友可以了解下

概述

循環(huán)依賴就是依賴關(guān)系形成環(huán),比如最簡(jiǎn)單的循環(huán)依賴:A對(duì)象依賴B,B對(duì)象依賴A

屬性注入與循環(huán)依賴

  1. 如果是構(gòu)造器注入,如果循環(huán)依賴對(duì)象沒(méi)法構(gòu)建,因?yàn)檫€未實(shí)例化
  2. 如果是屬性注入但是作用域是prototype,spring不會(huì)緩存其對(duì)象實(shí)例,也不能處理循環(huán)依賴的情況
  3. 如果是屬性注入singleton的,其bean的實(shí)例化過(guò)程與屬性注入過(guò)程是分開(kāi)的,并且spring提供了三個(gè)map(就是大家說(shuō)三級(jí)緩存)來(lái)實(shí)現(xiàn)。

spring屬性注入處理循環(huán)依賴的方式

通過(guò)以下xml方式配置一個(gè)循環(huán)依賴的示例:

<bean id="person1" class="com.example.leetcode.spring.bean.Person">
  <property name="parent" ref="person2"></property>
  <property name="name" value="tom"></property>
</bean>

<bean id="person2" class="com.example.leetcode.spring.bean.Person">
  <property name="parent" ref="person1"></property>
  <property name="name" value="jack"></property>
</bean>

spring循環(huán)依賴處理幾個(gè)關(guān)鍵位置:

獲取bean對(duì)象

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

  final String beanName = transformedBeanName(name);
  Object bean;

  // 這里會(huì)檢查單例bean是否已經(jīng)在注冊(cè)表,并返回。
  // Eagerly check singleton cache for manually registered singletons.
  Object sharedInstance = getSingleton(beanName);
  if (sharedInstance != null && args == null) {
    if (logger.isTraceEnabled()) {
      if (isSingletonCurrentlyInCreation(beanName)) {
        logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
            "' that is not fully initialized yet - a consequence of a circular reference");
      }
      else {
        logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
      }
    }
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  }
  ...
}

DefaultSingletonBeanRegistry(單例對(duì)象注冊(cè)表)的幾個(gè)關(guān)鍵屬性。

  // 用來(lái)存儲(chǔ)已經(jīng)創(chuàng)建好的單例對(duì)象
  /** Cache of singleton objects: bean name to bean instance. */
  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

  // 用來(lái)存儲(chǔ)單例beanname到ObjectFactory的映射
  /** Cache of singleton factories: bean name to ObjectFactory. */
  private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

  // 用來(lái)提前存儲(chǔ)還未初始化好的單例對(duì)象
  /** Cache of early singleton objects: bean name to bean instance. */
  private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

DefaultSingletonBeanRegistry.getSingleton()的實(shí)現(xiàn).

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  Object singletonObject = this.singletonObjects.get(beanName);
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    synchronized (this.singletonObjects) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
        if (singletonFactory != null) {
          singletonObject = singletonFactory.getObject();
          this.earlySingletonObjects.put(beanName, singletonObject);
          this.singletonFactories.remove(beanName);
        }
      }
    }
  }
  return singletonObject;
}

AbstractAutowireCapableBeanFactory.doCreateBean創(chuàng)建對(duì)象與注入屬性

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
  ...
  instanceWrapper = createBeanInstance(beanName, mbd, args);
  ...
  // 檢查是否提前將單例bean存入緩存
  boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    isSingletonCurrentlyInCreation(beanName));
  if (earlySingletonExposure) {
    if (logger.isTraceEnabled()) {
      logger.trace("Eagerly caching bean '" + beanName +
          "' to allow for resolving potential circular references");
    }
    // 這里將beanname與工廠映射放入緩存注冊(cè)表中(也就是上面的singletonFactories)
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  }
  
  ...
  // 注入依賴屬性
  populateBean(beanName, mbd, instanceWrapper);
  ...
        
}

假設(shè)我們從beanfactory獲取person1對(duì)象, 循環(huán)依賴處理流程如下:

1.通過(guò)AbstractBeanFactory.doGetBean("persion1")獲取對(duì)象

2.因?yàn)橐婚_(kāi)始通過(guò)DefaultSingletonBeanRegistry.getSingleton()什么都沒(méi)有,進(jìn)入AbstractAutowireCapableBeanFactory.doCreateBean()進(jìn)行創(chuàng)建

3.AutowireCapableBeanFactory.doCreateBean()里面執(zhí)行完創(chuàng)建邏輯,因?yàn)槭莝ingleton將beanname與工廠的映射加入到addSingletonFactory()到緩存

4.開(kāi)始處理person1對(duì)象的屬性依賴populateBean()

5.當(dāng)發(fā)現(xiàn)person1的parent屬性是一個(gè)引用時(shí),通過(guò)beanfactory.getBean("person2")獲取依賴對(duì)象(org.springframework.beans.factory.support.BeanDefinitionValueResolver#resolveReference)

6.此時(shí)進(jìn)入person2的創(chuàng)建流程, person2也沒(méi)有緩存,開(kāi)始實(shí)例化并加入到addSingletonFactory()到緩存

7.person2在通過(guò)populateBean()注入屬性依賴發(fā)現(xiàn)依賴person1, 此時(shí)通過(guò)beanfactory.getBean("person1")獲取依賴對(duì)象

8.此時(shí)AbstractBeanFactory.doGetBean("persion1")獲取對(duì)象執(zhí)行到getSingleton("person1")進(jìn)行以下判斷:

  • 從singletonObjects.get(beanName)獲取到null
  • 進(jìn)入if條件,對(duì)singletonObjects同步
  • 從earlySingletonObjects.get(beanName);獲取也為null
  • 進(jìn)入內(nèi)層if,通過(guò)singletonFactories.get(beanName);獲取到最開(kāi)始bean實(shí)例化之后的beanname與工廠緩存信息
  • 獲取到僅實(shí)例化完成的bean,并earlySingletonObjects.put(beanName, singletonObject);
  • 然后刪除singletonFactories.remove(beanName);

9.此時(shí)從getSingleton("person1")返回了一個(gè)僅實(shí)例化尚未注入的bean引用

10.person2在第7步獲取到person1僅實(shí)例化未注入的對(duì)象引用。

11.person2完成屬性注入并返回。

12.person2被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)緩存,并刪除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);

13.person1在5步獲取到person2的對(duì)象并完成屬性注入

14.person1對(duì)象返回(因?yàn)橐婚_(kāi)始person2獲取的是person1的引用,此時(shí)person1完成注入是能看到注入后的對(duì)象)

15.person1被addSingleton(beanName, singletonObject);中singletonObjects.put(beanName, singletonObject)緩存,并刪除singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);

16.返回最終的person1對(duì)象

關(guān)于三個(gè)map(三級(jí)緩存)

在出現(xiàn)循環(huán)依賴時(shí),三個(gè)map之間的流程如下:

先從singletonFactories獲取工廠,并通過(guò)getObject獲取對(duì)象并移除緩存,將對(duì)象緩存到earlySingletonObjects
通過(guò)earlySingletonObjects獲取提前曝光的對(duì)象
對(duì)象創(chuàng)建并初始化完成之后,對(duì)象信息保留在singletonObjects并移除過(guò)earlySingletonObjects中的緩存

earlySingletonObjects二級(jí)緩存是雞肋嗎?

earlySingletonObjects緩存的目的是,通過(guò)三級(jí)緩存在獲取對(duì)象會(huì)執(zhí)行一些列的后置處理器,通過(guò)earlySingletonObjects來(lái)緩存提升性能。

以上就是spring解決循環(huán)依賴的詳細(xì)內(nèi)容,更多關(guān)于sping 循環(huán)依賴的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring init-method與destroy-method屬性的用法解析

    Spring init-method與destroy-method屬性的用法解析

    這篇文章主要介紹了Spring init-method與destroy-method屬性的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java BigDecimal中divide方法案例詳解

    Java BigDecimal中divide方法案例詳解

    這篇文章主要介紹了Java BigDecimal中divide方法案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringCloud 如何提取公共配置

    SpringCloud 如何提取公共配置

    這篇文章主要介紹了SpringCloud 提取公共配置的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • kafka生產(chǎn)者和消費(fèi)者的javaAPI的示例代碼

    kafka生產(chǎn)者和消費(fèi)者的javaAPI的示例代碼

    這篇文章主要介紹了kafka生產(chǎn)者和消費(fèi)者的javaAPI的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • SpringCloud之Feign遠(yuǎn)程接口映射的實(shí)現(xiàn)

    SpringCloud之Feign遠(yuǎn)程接口映射的實(shí)現(xiàn)

    這篇文章主要介紹了SpringCloud之Feign遠(yuǎn)程接口映射的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 全面了解servlet中cookie的使用方法

    全面了解servlet中cookie的使用方法

    下面小編就為大家?guī)?lái)一篇全面了解servlet中cookie的使用方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-06-06
  • spring profile 多環(huán)境配置管理詳解

    spring profile 多環(huán)境配置管理詳解

    這篇文章主要介紹了 spring profile 多環(huán)境配置管理詳解的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • 淺談Java中hashCode的正確求值方法

    淺談Java中hashCode的正確求值方法

    這篇文章主要介紹了淺談Java中hashCode的正確求值方法,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • Spring RestTemplate具體使用詳解

    Spring RestTemplate具體使用詳解

    這篇文章主要介紹了Spring RestTemplate具體使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-04-04
  • Java?CyclicBarrier錯(cuò)誤使用的實(shí)例

    Java?CyclicBarrier錯(cuò)誤使用的實(shí)例

    文章描述了一個(gè)Java程序使用CyclicBarrier實(shí)現(xiàn)兩個(gè)線程交替打印字母和數(shù)字時(shí)遇到的問(wèn)題,由于線程執(zhí)行順序不當(dāng),導(dǎo)致輸出結(jié)果與預(yù)期不符,通過(guò)調(diào)整線程的等待和打印順序,解決了問(wèn)題,文章還提供了一個(gè)控制流圖來(lái)詳細(xì)解釋修改前后的程序邏輯
    2025-01-01

最新評(píng)論

剑河县| 南丰县| 攀枝花市| 许昌县| 元阳县| 荣昌县| 霸州市| 大洼县| 长春市| 苏尼特右旗| 辉南县| 涿鹿县| 台中市| 中宁县| 惠水县| 临澧县| 汝州市| 兴安盟| 元朗区| 梧州市| 凤阳县| 天台县| 清水河县| 乳源| 酒泉市| 湄潭县| 湘潭市| 岳西县| 天台县| 镇巴县| 隆德县| 潮安县| 宁津县| 大港区| 仁化县| 博客| 莒南县| 天镇县| 红安县| 车险| 漳浦县|