欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

概述

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

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

  1. 如果是構(gòu)造器注入,如果循環(huán)依賴對象沒法構(gòu)建,因為還未實例化
  2. 如果是屬性注入但是作用域是prototype,spring不會緩存其對象實例,也不能處理循環(huán)依賴的情況
  3. 如果是屬性注入singleton的,其bean的實例化過程與屬性注入過程是分開的,并且spring提供了三個map(就是大家說三級緩存)來實現(xiàn)。

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

通過以下xml方式配置一個循環(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)依賴處理幾個關鍵位置:

獲取bean對象

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;

  // 這里會檢查單例bean是否已經(jīng)在注冊表,并返回。
  // 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(單例對象注冊表)的幾個關鍵屬性。

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

  // 用來存儲單例beanname到ObjectFactory的映射
  /** 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 HashMap<>(16);

DefaultSingletonBeanRegistry.getSingleton()的實現(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)建對象與注入屬性

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與工廠映射放入緩存注冊表中(也就是上面的singletonFactories)
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  }
  
  ...
  // 注入依賴屬性
  populateBean(beanName, mbd, instanceWrapper);
  ...
        
}

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

1.通過AbstractBeanFactory.doGetBean("persion1")獲取對象

2.因為一開始通過DefaultSingletonBeanRegistry.getSingleton()什么都沒有,進入AbstractAutowireCapableBeanFactory.doCreateBean()進行創(chuàng)建

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

4.開始處理person1對象的屬性依賴populateBean()

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

6.此時進入person2的創(chuàng)建流程, person2也沒有緩存,開始實例化并加入到addSingletonFactory()到緩存

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

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

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

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

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

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

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

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

14.person1對象返回(因為一開始person2獲取的是person1的引用,此時person1完成注入是能看到注入后的對象)

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

16.返回最終的person1對象

關于三個map(三級緩存)

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

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

earlySingletonObjects二級緩存是雞肋嗎?

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

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

相關文章

  • 利用spring boot如何快速啟動一個web項目詳解

    利用spring boot如何快速啟動一個web項目詳解

    這篇文章主要給大家介紹了關于利用spring boot如何快速啟動一個web項目的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧、
    2017-12-12
  • Java super和this的對比及使用

    Java super和this的對比及使用

    這篇文章主要介紹了Java super和this的對比及使用的相關資料,java中this與super會經(jīng)常在使用的時候混淆,需要的朋友可以參考下
    2017-08-08
  • java的Jackson將json字符串轉(zhuǎn)換成泛型List

    java的Jackson將json字符串轉(zhuǎn)換成泛型List

    這篇文章主要介紹了java的Jackson將json字符串轉(zhuǎn)換成泛型List ,這里整理了詳細的代碼,有需要的小伙伴可以參考下。
    2017-02-02
  • Java實現(xiàn)帶GUI的氣泡詩詞效果

    Java實現(xiàn)帶GUI的氣泡詩詞效果

    這篇文章主要為大家介紹了如何利用Java實現(xiàn)帶GUI的氣泡詩詞效果,文中的示例代碼講解詳細,對我們學習Java有一定幫助,感興趣的可以了解一下
    2022-12-12
  • java實現(xiàn)JSON字符串格式化輸出

    java實現(xiàn)JSON字符串格式化輸出

    這篇文章主要為大家詳細介紹了如何使用java實現(xiàn)JSON字符串格式化輸出,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以了解下
    2024-01-01
  • java 字節(jié)流和字符流的區(qū)別詳解

    java 字節(jié)流和字符流的區(qū)別詳解

    這篇文章主要介紹了java 字節(jié)流和字符流的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • Java操作集合工具類Collections使用詳解

    Java操作集合工具類Collections使用詳解

    這篇文章主要介紹了java操作集合工具類Collections使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • JAVA CyclicBarrier 示例源碼解析

    JAVA CyclicBarrier 示例源碼解析

    CyclicBarrier是一個強大的同步工具,可以幫助我們實現(xiàn)復雜的多線程協(xié)同任務,這篇文章主要介紹了JAVA CyclicBarrier 示例源碼解析,通過本文,我們深入了解了CyclicBarrier的源碼實現(xiàn),并通過一個簡單的示例演示了它的用法,需要的朋友可以參考下
    2023-12-12
  • 說說@ModelAttribute在父類和子類中的執(zhí)行順序

    說說@ModelAttribute在父類和子類中的執(zhí)行順序

    這篇文章主要介紹了@ModelAttribute在父類和子類中的執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • idea手動執(zhí)行maven命令的三種實現(xiàn)方式

    idea手動執(zhí)行maven命令的三種實現(xiàn)方式

    這篇文章主要介紹了idea手動執(zhí)行maven命令的三種實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08

最新評論