91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring源碼是怎么解決Bean的循環依賴

發布時間:2021-12-14 12:29:29 來源:億速云 閱讀:168 作者:小新 欄目:開發技術

這篇文章給大家分享的是有關Spring源碼是怎么解決Bean的循環依賴的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

首先需要明白一點,只有scop為(singleton)單例類型的Bean,spring才支持循環依賴。

scope為(prototype)原型類型的Bean是不支持的,它每次調用都會創建一個新的實例,spring 在實例化bean的時候會先實例化bean的各種屬性依賴,如果TestA TestB是原型類型且相互依賴則會出現new TestA 的時候,先new TestB,然后new TestB的時候又去new TestA會出現無限套娃的情況。

兩個單例testA testB 互相依賴的實例化過程

Spring容器創建單例“testA”bean,首先根據無參構造器創建bean,并暴露一個“ObjectFactory”用于返回一個提前暴露正在創建中的bean,并將“testA”標識符放到“當前創建bean池”,然后進行setter注入“testB”。

Spring容器創建單例“testB”bean,首先根據無參構造器創建bean,并暴露一個“ObjectFactory”用于返回一個提前暴露正在創建中的bean,并將“testB”標識符放到“當前創建bean池”,然后進行setter注入“testA”,此時由于通過 暴露"ObjectFactory" 已提前暴露了一個正在創建中的"testA" bean,所以直接注入,完成testB的創建,注入testA中,再完成testA的創建。

源碼中的實現方式

首先了解一下創建Bean過程中最重要的三個map

以下三個Map均來自于 DefaultSingletonBeanRegistry

Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
  • singletonObjects:用于保存BeanName和創建bean實例之間的關系,bean name 一> bean instance。

  • singletonFactories:用于保存BeanName和創建bean的工廠之間的關系,bean name 一>ObjectFactory。

  • earlySingletonObjects:也是保存BeanName和創建bean實例之間的關系,與singletonObjects的不同之處在于,當一個單例bean被放到這里面后,那么當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用。

總結:后面兩個Map實際上就是為了輔助第一個Map緩存Bean的實例,完成后數據就在后面兩個Map中清掉了。

測試代碼:

// 1. 引入依賴,springboot項目只需要這一個依賴即可測試
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
// 2. 兩個測試類
@Component
public class TestA {
    @Autowired
    private TestB testB;
}
@Component
public class TestB {
    @Autowired
    private TestA testA;
}

注意:下面所有的方法都只是源碼的部分截取,把我認為重要的邏輯放在這里的,大家閱讀時,可提前在IDE中打開文中提到的幾個類,在相應方法處,打上斷點可以直接調試,bean的實例化過程就一目了然了。

1. AbstractBeanFactory 類中 getBean方法

public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
  throws BeansException {
 return doGetBean(name, requiredType, args, false);
}

2. AbstractBeanFactory 類中 doGetBean方法

// 
// 2.1 從緩存中獲取實例Bean,第一次肯定沒有,為null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
 beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else{
 // Create bean instance.
 if (mbd.isSingleton()) {
  // 2.2 獲取緩存中的實例
  sharedInstance = getSingleton(beanName, () -> {
   try {
    // 2.3 調用創建Bean實例的方法
    return createBean(beanName, mbd, args);
   } 
  });
  beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
 }
}

3. DefaultSingletonBeanRegistry 類中 getSingleton方法,2.1調用的就是這里的3.1

// 3.1
@Override
@Nullable
public Object getSingleton(String beanName) {
 return getSingleton(beanName, true);
}
// 3.2
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
 // Quick check for existing instance without full singleton lock
 Object singletonObject = this.singletonObjects.get(beanName);
 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  singletonObject = this.earlySingletonObjects.get(beanName);
  if (singletonObject == null && allowEarlyReference) {
   synchronized (this.singletonObjects) {
    // Consistent creation of early reference within full singleton lock
    singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null) {
     singletonObject = this.earlySingletonObjects.get(beanName);
     if (singletonObject == null) {
      ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
      if (singletonFactory != null) {
       singletonObject = singletonFactory.getObject();
       this.earlySingletonObjects.put(beanName, singletonObject);
       this.singletonFactories.remove(beanName);
      }
     }
    }
   }
  }
 }
 return singletonObject;
}

3.1和3.2后面會反復獲取的,第一次因為isSingletonCurrentlyInCreation(beanName)返回false,所以返回null

4. DefaultSingletonBeanRegistry 類中 getSingleton方法,獲取ObjectFactory,2.2就是調用的這里

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
 synchronized (this.singletonObjects) {
  Object singletonObject = this.singletonObjects.get(beanName);
  if (singletonObject == null) {
   beforeSingletonCreation(beanName);
   boolean newSingleton = false;
   try {
    // 4.0.1
    singletonObject = singletonFactory.getObject();
    newSingleton = true;
   }
   finally {
    afterSingletonCreation(beanName);
   }
   if (newSingleton) {
    // 4.0.2
    addSingleton(beanName, singletonObject);
   }
  }
  return singletonObject;
 }
}
protected void addSingleton(String beanName, Object singletonObject) {
 synchronized (this.singletonObjects) {
  this.singletonObjects.put(beanName, singletonObject);
  this.singletonFactories.remove(beanName);
  this.earlySingletonObjects.remove(beanName);
  this.registeredSingletons.add(beanName);
 }
}

這面重點分析beforeSingletonCreation 、afterSingletonCreation 和 addSingleton這三個方法

4.1 DefaultSingletonBeanRegistry 中 beforeSingletonCreation方法 和 afterSingletonCreation方法

protected void beforeSingletonCreation(String beanName) {
 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
  throw new BeanCurrentlyInCreationException(beanName);
 }
}
protected void afterSingletonCreation(String beanName) {
 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
  throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
 }
}

重點:這兩個方法的目的就是為 singletonsCurrentlyInCreation 這個set集合添加和刪除當前創建的Bean,為后續處理做鋪墊,addSingleton方法主要是對Bean緩存map的維護。

4.2 現在回到第4步的4.0.1的方法中,singletonObject = singletonFactory.getObject();這行代碼就是正真獲取實例對象的地方,singletonFactory 是怎么拿到的呢,這就要回到第2步的2.3步驟中,通過createBean方法返回了ObjectFactory類型的singletonFactory,下面看createBean是如何創建Bean的:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {  
 try {
  Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  return beanInstance;
 } 
}
// 看過一些spring源碼的都應該明白spring真正做事情的都是以doXXX開頭的,這里也不例外
// 相信大家都已經明白真正創建Bean是由doCreateBean方法實現的,下面我們繼續分析這個方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
 BeanWrapper instanceWrapper = null;
 if (instanceWrapper == null) {
  instanceWrapper = createBeanInstance(beanName, mbd, args);
 }
 Object bean = instanceWrapper.getWrappedInstance();
 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences
  && isSingletonCurrentlyInCreation(beanName));
 if (earlySingletonExposure) {
  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
 }
 Object exposedObject = bean;
 try {
  // 4.3 填充Bean的屬性,依賴bean就是這里初始化的
  populateBean(beanName, mbd, instanceWrapper);
  exposedObject = initializeBean(beanName, exposedObject, mbd);
 }
 if (earlySingletonExposure) {
  // 4.4 再次獲取緩存中的實例,注意這里可以從兩個緩存處獲取,第一個是earlySingletonObjects map,第二個是singletonFactories map獲取
  Object earlySingletonReference = getSingleton(beanName, false);
  if (earlySingletonReference != null) {
   if (exposedObject == bean) {
    exposedObject = earlySingletonReference;
   }
  }
 }
 return exposedObject;
}
// isSingletonCurrentlyInCreation方法
public boolean isSingletonCurrentlyInCreation(String beanName) {
 return this.singletonsCurrentlyInCreation.contains(beanName);
}
// addSingletonFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
 Assert.notNull(singletonFactory, "Singleton factory must not be null");
 synchronized (this.singletonObjects) {
 if (!this.singletonObjects.containsKey(beanName)) {
  this.singletonFactories.put(beanName, singletonFactory);
  this.earlySingletonObjects.remove(beanName);
  this.registeredSingletons.add(beanName);
 }
}

重要流程梳理

1.doCreateBean中主要分為兩部分,第一部分通過instanceWrapper得到BeanFactory的實例,內部由反射實現,這里我們不多做分析,變量earlySingletonExposure,它由三部分得到,前面兩個都很容易理解,第三部分則出現了我們在4.1中做鋪墊的集合 singletonsCurrentlyInCreation。由于在4.1中已經設置了,所以earlySingletonExposure肯定為true,因此執行addSingletonFacatory為singletonFactories map賦值,完成了beanName -> ObjectFactory的映射

2.populateBean方法中則會完成對Bean依賴屬性的注入,因此代碼走到4.3的時候,testA的創建就停止了,會回到第一步去獲取testB,然后又是對testB的創建,最后會再次走到4.3,完成testA 和 testB 的ObjectFactory的映射,即將它們放入 singletonFactories map緩存中。

3.創建testB 再次走到4.3的時候,又會去初始化testB的依賴 testA,此時會再次去第一步獲取,再次走到2.1的時候,因為testA的ObjectFactory是有值的,所以通過它能夠獲取到testA 的singletonObject,此時就把testA 的實例放入了 earlySingletonObjects中,只不過此時的testA實例是不完整的,還沒有完成屬性testB依賴的初始化。最后返回testA的singletonObject引用,完成testB對其依賴testA的初始化,然后再去 4.4 獲取testB的緩存,這里依舊是沒有的,然后返回到4.0.2處,將testB加入singletonObjects map緩存,并移除testB在singletonFactories中的緩存,這里testB 在 earlySingletonObjects中實際上是沒有值的,當然有的話也會移除,因為singletonObjects 中已經拿到值了,所以另外兩個輔助map就不用保留數據了。

4.上面已經完成testB的初始化并放入singletonObjects 緩存了,繼續走,就又回到了4.3,繼續完成對testA的創建,走到4.4的時候,繼續去緩存中獲取testA,因為之前已經把testA放入earlySingletonObjects map中了,所以4.4是直接能夠獲取到testA的實例的。

5.繼續走,就又來到了4.0.2,不過這次是針對testA的,addSingleton方法中會把testA的實例給放入singletonObjects map緩存中,同時移除singletonFactories 和 earlySingletonObjects map緩存的testA,完成testA和testB的實例化。

感謝各位的閱讀!關于“Spring源碼是怎么解決Bean的循環依賴”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

加查县| 广灵县| 栾城县| 阳信县| 明溪县| 洱源县| 泰顺县| 海兴县| 贡觉县| 方正县| 雷州市| 玉田县| 曲阜市| 安国市| 崇明县| 旬阳县| 诸暨市| 开化县| 宝应县| 吉安县| 扶风县| 沙田区| 留坝县| 嘉义市| 西林县| 宜昌市| 滨海县| 时尚| 红原县| 蕲春县| 肥西县| 微博| 红河县| 青田县| 凤翔县| 伊川县| 饶阳县| 武鸣县| 西丰县| 云阳县| 棋牌|