溫馨提示×

溫馨提示×

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

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

如何用spring源碼剖析spring bean循環依賴

發布時間:2021-12-28 15:04:25 來源:億速云 閱讀:197 作者:柒染 欄目:大數據

如何用Spring源碼剖析Spring Bean循環依賴

目錄

  1. 引言
  2. Spring Bean的生命周期
  3. 循環依賴的定義與問題
  4. Spring中的循環依賴解決方案
  5. 源碼分析
  6. 常見問題與解決方案
  7. 總結

引言

在Spring框架中,Bean的依賴注入是其核心功能之一。然而,當Bean之間存在循環依賴時,Spring如何解決這一問題成為了開發者關注的焦點。本文將深入剖析Spring源碼,探討Spring如何通過三級緩存機制解決Bean的循環依賴問題。

Spring Bean的生命周期

在深入探討循環依賴之前,我們需要了解Spring Bean的生命周期。Spring Bean的生命周期大致可以分為以下幾個階段:

  1. 實例化:通過反射機制創建Bean的實例。
  2. 屬性填充:將配置文件中定義的屬性值注入到Bean實例中。
  3. 初始化:調用Bean的初始化方法(如@PostConstruct注解的方法)。
  4. 使用:Bean可以被應用程序使用。
  5. 銷毀:當容器關閉時,調用Bean的銷毀方法(如@PreDestroy注解的方法)。

循環依賴的定義與問題

循環依賴指的是兩個或多個Bean相互依賴,形成一個閉環。例如,Bean A依賴Bean B,而Bean B又依賴Bean A。這種情況下,Spring在創建Bean時會陷入死循環,導致容器無法正常啟動。

Spring中的循環依賴解決方案

Spring通過三級緩存機制解決了Bean的循環依賴問題。具體來說,Spring在Bean的創建過程中使用了三個緩存:

  1. singletonObjects:存放完全初始化好的單例Bean。
  2. earlySingletonObjects:存放提前暴露的單例Bean(尚未完成屬性填充和初始化)。
  3. singletonFactories:存放Bean的工廠對象,用于創建提前暴露的Bean。

4.1 三級緩存機制

三級緩存機制的核心思想是在Bean的創建過程中,提前暴露一個尚未完全初始化的Bean實例,以便其他Bean可以引用它。具體步驟如下:

  1. 當Spring開始創建Bean A時,首先將Bean A的工廠對象放入singletonFactories緩存中。
  2. 在Bean A的屬性填充階段,如果發現需要注入Bean B,Spring會嘗試從緩存中獲取Bean B。
  3. 如果Bean B尚未創建,Spring會開始創建Bean B,并將Bean B的工廠對象放入singletonFactories緩存中。
  4. 在Bean B的屬性填充階段,如果發現需要注入Bean A,Spring會從singletonFactories緩存中獲取Bean A的工廠對象,并創建一個提前暴露的Bean A實例。
  5. 將提前暴露的Bean A實例放入earlySingletonObjects緩存中,并注入到Bean B中。
  6. Bean B完成屬性填充和初始化后,將其放入singletonObjects緩存中。
  7. 最后,Bean A完成屬性填充和初始化,并將其放入singletonObjects緩存中。

4.2 提前暴露對象

提前暴露對象是解決循環依賴的關鍵。通過提前暴露一個尚未完全初始化的Bean實例,Spring可以打破循環依賴的死鎖。

4.3 代理對象的處理

在Spring AOP中,代理對象的創建可能會影響循環依賴的解決。Spring通過SmartInstantiationAwareBeanPostProcessor接口來處理代理對象的創建,確保在循環依賴的情況下,代理對象能夠正確創建和注入。

源碼分析

5.1 Bean的創建過程

Spring Bean的創建過程主要在AbstractAutowireCapableBeanFactory類中實現。以下是Bean創建的主要步驟:

  1. 實例化:通過createBeanInstance方法創建Bean的實例。
  2. 屬性填充:通過populateBean方法將屬性值注入到Bean實例中。
  3. 初始化:通過initializeBean方法調用Bean的初始化方法。

5.2 三級緩存的實現

三級緩存的實現主要在DefaultSingletonBeanRegistry類中。以下是三級緩存的主要代碼:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    /** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    /** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    // 其他代碼...
}

5.3 循環依賴的解決過程

循環依賴的解決過程主要在AbstractAutowireCapableBeanFactory類的doCreateBean方法中實現。以下是主要代碼:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    // 實例化Bean
    BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
    final Object bean = instanceWrapper.getWrappedInstance();

    // 提前暴露Bean的工廠對象
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // 屬性填充
    populateBean(beanName, mbd, instanceWrapper);

    // 初始化Bean
    exposedObject = initializeBean(beanName, exposedObject, mbd);

    return exposedObject;
}

常見問題與解決方案

6.1 構造器注入的循環依賴

構造器注入的循環依賴無法通過三級緩存機制解決,因為構造器注入要求在Bean實例化時就完成依賴注入。解決方案是使用@Lazy注解延遲加載依賴。

6.2 原型Bean的循環依賴

原型Bean的循環依賴無法通過三級緩存機制解決,因為每次獲取原型Bean時都會創建一個新的實例。解決方案是盡量避免在原型Bean中使用循環依賴。

6.3 AOP代理與循環依賴

AOP代理對象的創建可能會影響循環依賴的解決。Spring通過SmartInstantiationAwareBeanPostProcessor接口確保代理對象能夠正確創建和注入。

總結

Spring通過三級緩存機制成功解決了Bean的循環依賴問題。通過提前暴露尚未完全初始化的Bean實例,Spring打破了循環依賴的死鎖。然而,構造器注入和原型Bean的循環依賴仍然需要開發者特別注意。通過深入理解Spring源碼,開發者可以更好地應對復雜的依賴注入場景。

向AI問一下細節

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

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女