死磕Spring之IoC篇 - 開啟 Bean 的加載


該系列文章是本人在學習 Spring 的過程中總結下來的,里面涉及到相關源碼,可能對讀者不太友好,請結合我的源碼注釋 Spring 源碼分析 GitHub 地址 進行閱讀

Spring 版本:5.1.14.RELEASE

開始閱讀這一系列文章之前,建議先查看《深入了解 Spring IoC(面試題)》這一篇文章

該系列其他文章請查看:《死磕 Spring 之 IoC 篇 - 文章導讀》

開啟 Bean 的加載

前面的一些列文章對面向資源(XML、Properties)面向注解定義的 Bean 是如何被解析成 BeanDefinition(Bean 的“前身”),並保存至 BeanDefinitionRegistry 注冊中心里面,實際也是通過 ConcurrentHashMap 進行保存。

Spring 底層 IoC 容器 DefaultListableBeanFactory,實現了 BeanFactory 和 BeanDefinitionRegistry 接口,這個時候它處於“就緒狀態”,當我們顯示或者隱式地調用 getBean(...) 方法時,會觸發加載 Bean 階段,獲取對應的 Bean。在該方法中,如果是單例模式會先從緩存中獲取,已有則直接返回,沒有則根據 BeanDefinition 開始初始化這個 Bean。

BeanFactory 體系結構

先來看看 BeanFactory 接口的繼承關系

簡單描述這些接口:

  • org.springframework.beans.factory.BeanFactory,Spring IoC 容器最基礎的接口,提供依賴查找單個 Bean 的功能

  • org.springframework.beans.factory.ListableBeanFactory,繼承 BeanFactory 接口,提供依賴查找多個 Bean 的功能

  • org.springframework.beans.factory.HierarchicalBeanFactory,繼承 BeanFactory 接口,提供獲取父 BeanFactory 的功能,具有層次性

  • org.springframework.beans.factory.config.ConfigurableBeanFactory,繼承 HierarchicalBeanFactory 接口,提供可操作內部相關組件的功能,具有可配置性

  • org.springframework.beans.factory.config.AutowireCapableBeanFactory,繼承 BeanFactory 接口,提供可注入的功能,支持依賴注入

  • org.springframework.beans.factory.config.ConfigurableListableBeanFactory,繼承上面所有接口,綜合所有特性,還提供可提前初始化所有單例 Bean 的功能

通過這些接口的名稱可以大致了解其用意,接下來我們來看看它們的實現類的繼承關系

簡單描述這些實現類:

  • org.springframework.beans.factory.support.AbstractBeanFactory 抽象類,實現 ConfigurableBeanFactory 接口,基礎實現類,Bean 的創建過程交由子類實現
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 抽象類,繼承 AbstractBeanFactory,實現 AutowireCapableBeanFactory 接口,完成 Bean 的創建
  • org.springframework.beans.factory.support.DefaultListableBeanFactory,Spring 底層 IoC 容器,依賴注入的底層實現

其他的接口和類和 BeanDefinition 注冊中心,別名注冊中心,單例 Bean 注冊中心相關;右下角的 ApplicationContext 與 Spring 應用上下文有關,它的整個體系這里不做展述,在后面的文章進行分析

AbstractBeanFactory

org.springframework.beans.factory.support.AbstractBeanFactory 抽象類,實現 ConfigurableBeanFactory 接口,BeanFactory 的基礎實現類,提供依賴查找方法,可獲取 Bean 對象,接下來我們來看看依賴查找的實現

getBean 方法

getBean(String name) 方法,根據名稱獲取 Bean,當然還有許多重載方法,如下:

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
}

@Override
public Object getBean(String name, Object... args) throws BeansException {
    return doGetBean(name, null, args, false);
}

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

最終都會調用 doGetBean(...) 這個方法

當我們顯示或者隱式地調用這個方法時,會觸發 Bean 的加載;你是否會有疑問,我們使用 Spring 的過程中並不會調用這個方法去獲取 Bean,那這個方法會被誰調用呢?在 ConfigurableListableBeanFactory 接口中提供提前初始化所有單例 Bean 的功能,在 Spring 應用上下文(ApplicationContext)刷新階段會提前初始化所有的單例 Bean,這個提前初始化也是調用 getBean 這個方法,這部分內容在后續分析 Spring 應用上下文的生命周期會講到

【核心】doGetBean 方法

doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) 方法,獲取一個 Bean,方法如下:

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

    // <1> 獲取 `beanName`
    // 因為入參 `name` 可能是別名,也可能是 FactoryBean 類型 Bean 的名稱(`&` 開頭,需要去除)
    // 所以需要獲取真實的 beanName
    final String beanName = transformedBeanName(name);
    Object bean;

    // <2> 先從緩存(僅緩存單例 Bean )中獲取 Bean 對象,這里緩存指的是 `3` 個 Map
    // 緩存中也可能是正在初始化的 Bean,可以避免**循環依賴注入**引起的問題
    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    // <3> 若從緩存中獲取到對應的 Bean,且 `args` 參數為空
    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 + "'");
            }
        }
        // <3.1> 獲取 Bean 的目標對象,`scopedInstance` 非 FactoryBean 類型直接返回
        // 否則,調用 FactoryBean#getObject() 獲取目標對象
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    // 緩存中沒有對應的 Bean,則開啟 Bean 的加載
    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        // <4> 如果**非單例模式**下的 Bean 正在創建,這里又開始創建,表明存在循環依賴,則直接拋出異常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        BeanFactory parentBeanFactory = getParentBeanFactory();
        // <5> 如果從當前容器中沒有找到對應的 BeanDefinition,則從父容器中加載(如果存在父容器)
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            // <5.1> 獲取 `beanName`,因為可能是別名,則進行處理
            // 和第 `1` 步不同,不需要對 `&` 進行處理,因為進入父容器重新依賴查找
            String nameToLookup = originalBeanName(name);
            // <5.2> 若為 AbstractBeanFactory 類型,委托父容器的 doGetBean 方法進行處理
            // 否則,就是非 Spring IoC 容器,根據參數調用相應的 `getBean(...)`方法
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

        // <6> 如果不是僅僅做類型檢查,則表示需要創建 Bean,將 `beanName` 標記為已創建過
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            // <7> 從容器中獲取 `beanName` 對應的的 RootBeanDefinition(合並后)
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 檢查是否為抽象類
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            // <8> 獲取當前正在創建的 Bean 所依賴對象集合(`depends-on` 配置的依賴)
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    // <8.1> 檢測是否存在循環依賴,存在則拋出異常
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // <8.2> 將 `beanName` 與 `dep` 之間依賴的關系進行緩存
                    registerDependentBean(dep, beanName);
                    try {
                        // <8.3> 先創建好依賴的 Bean(重新調用 `getBean(...)` 方法)
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // Create bean instance.
            // <9> 開始創建 Bean,不同模式創建方式不同
            if (mbd.isSingleton()) { // <9.1> 單例模式
                /*
                 * <9.1.1> 創建 Bean,成功創建則進行緩存,並移除緩存的早期對象
                 * 創建過程實際調用的下面這個 `createBean(...)` 方法
                 */
                sharedInstance = getSingleton(beanName,
                        // ObjectFactory 實現類
                        () -> {
                            try {
                                // **【核心】** 創建 Bean
                                return createBean(beanName, mbd, args);
                            } catch (BeansException ex) {
                                // Explicitly remove instance from singleton cache: It might have been put there
                                // eagerly by the creation process, to allow for circular reference resolution.
                                // Also remove any beans that received a temporary reference to the bean.
                                // 如果創建過程出現異常,則顯式地從緩存中刪除當前 Bean 相關信息
                                // 在單例模式下為了解決循環依賴,創建過程會緩存早期對象,這里需要進行刪除
                                destroySingleton(beanName);
                                throw ex;
                            }
                });
                // <9.1.2> 獲取 Bean 的目標對象,`scopedInstance` 非 FactoryBean 類型直接返回
                // 否則,調用 FactoryBean#getObject() 獲取目標對象
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // <9.2> 原型模式
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    // <9.2.1> 將 `beanName` 標記為原型模式正在創建
                    beforePrototypeCreation(beanName);
                    // <9.2.2> **【核心】** 創建 Bean
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    // <9.2.3> 將 `beanName` 標記為不在創建中,照應第 `9.2.1` 步
                    afterPrototypeCreation(beanName);
                }
                // <9.2.4> 獲取 Bean 的目標對象,`scopedInstance` 非 FactoryBean 類型直接返回
                // 否則,調用 FactoryBean#getObject() 獲取目標對象
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            // <9.3> 其他模式
            else {
                // <9.3.1> 獲取該模式的 Scope 對象 `scope`,不存在則拋出異常
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    // <9.3.1> 從 `scope` 中獲取 `beanName` 對應的對象(看你的具體實現),不存在則執行**原型模式**的四個步驟進行創建
                    Object scopedInstance = scope.get(beanName, () -> {
                        // 將 `beanName` 標記為原型模式正在創建
                        beforePrototypeCreation(beanName);
                        try {
                            // **【核心】** 創建 Bean
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            // 將 `beanName` 標記為不在創建中,照應上一步
                            afterPrototypeCreation(beanName);
                        }
                    });
                    // 獲取 Bean 的目標對象,`scopedInstance` 非 FactoryBean 類型直接返回
                    // 否則,調用 FactoryBean#getObject() 獲取目標對象
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    // <10> 如果入參 `requiredType` 不為空,並且 Bean 不是該類型,則需要進行類型轉換
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            // <10.1> 通過類型轉換機制,將 Bean 轉換成 `requiredType` 類型
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            // <10.2> 轉換后的 Bean 為空則拋出異常
            if (convertedBean == null) {
                // 轉換失敗,拋出 BeanNotOfRequiredTypeException 異常
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            // <10.3> 返回類型轉換后的 Bean 對象
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    // <11> 返回獲取到的 Bean
    return (T) bean;
}

這個方法的處理過程有點長,如下:

  1. 獲取 beanName,因為入參 name 可能是別名,也可能是 FactoryBean 類型 Bean 的名稱(& 開頭,需要去除),所以需要獲取真實的 beanName

  2. 先從緩存(僅緩存單例 Bean )中獲取 Bean 對象,這里緩存指的是 3 個 Map;緩存中也可能是正在初始化的 Bean,可以避免循環依賴注入引起的問題

  3. 若從緩存中獲取到對應的 Bean,且 args 參數為空

    1. 【同】調用 getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) 方法

      獲取 Bean 的目標對象,scopedInstance 非 FactoryBean 類型直接返回,否則,調用 FactoryBean#getObject() 獲取目標對象


緩存中沒有對應的 Bean,則開啟 Bean 的加載

  1. 如果非單例模式下的 Bean 正在創建,這里又開始創建,表明存在循環依賴,則直接拋出異常

  2. 如果從當前容器中沒有找到對應的 BeanDefinition,則從父容器中加載(如果存在父容器)

    1. 獲取 beanName,因為可能是別名,則進行處理,和第 1 步不同,不需要對 & 進行處理,因為進入父容器重新依賴查找
    2. 若為 AbstractBeanFactory 類型,委托父容器的 doGetBean 方法進行處理;否則,就是非 Spring IoC 容器,根據參數調用相應的 getBean(...)方法
  3. 如果不是僅僅做類型檢查,則表示需要創建 Bean,將 beanName 標記為已創建過,在后面的循環依賴檢查中會使用到

  4. 從容器中獲取 beanName 對應的的 RootBeanDefinition(合並后),調用 getMergedLocalBeanDefinition(String beanName) 方法

  5. 獲取當前正在創建的 Bean 所依賴對象集合(depends-on 配置的依賴)

    1. 檢測是否存在循環依賴,存在則拋出異常
    2. beanNamedep 之間依賴的關系進行緩存
    3. 先創建好依賴的 Bean(重新調用 getBean(...) 方法)

  1. 開始創建 Bean,不同模式創建方式不同

    1. 單例模式

      1. 創建 Bean,成功創建則進行緩存,並移除緩存的早期對象,調用 getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法

        【核心】入參的 ObjectFactory 實現類就是調用的 AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]) 方法

      2. 【同】 和上面的 3.1 相同操作

    2. 原型模式

      1. beanName 標記為非單例模式正在創建
      2. 【核心】 創建 Bean,調用 AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]) 方法
      3. beanName 標記為不在創建中,照應第 9.2.1
      4. 【同】 和上面的 3.1 相同操作
    3. 其他模式

      1. 獲取該模式的 Scope 對象 scope,不存在則拋出異常
      2. scope 中獲取 beanName 對應的對象(看你的具體實現),不存在則執行原型模式的四個步驟進行創建

  1. 如果入參 requiredType 不為空,並且 Bean 不是該類型,則需要進行類型轉換

    1. 通過類型轉換機制,將 Bean 轉換成 requiredType 類型
    2. 轉換后的 Bean 為空則拋出異常
    3. 返回類型轉換后的 Bean 對象
  2. 返回獲取到的 Bean


概括:

  • 可以看到這個方法加載 Bean 的過程中,會先從緩存中獲取單例模式的 Bean;

  • 不管是從緩存中獲取的還是新創建的,都會進行處理,如果是 FactoryBean 類型則調用其 getObject() 獲取目標對象;

  • BeanFactory 可能有父容器,如果當前容器找不到 BeanDefinition 則會嘗試讓父容器創建;

  • 創建 Bean 的任務交由 AbstractAutowireCapableBeanFactory 去完成;

  • 如果獲取到的 Bean 不是我們想要類型,會通過類型轉換機制轉換成目標類型

接下來依次分析上述過程的相關步驟(doGetBean(...)

1. 獲取 beanName

對應代碼段:

// AbstractBeanFactory.java
final String beanName = transformedBeanName(name);

因為入參 name 可能是別名,也可能是 FactoryBean 類型 Bean 的名稱(& 開頭,需要去除),所以需要進行一番轉換,如下:

// AbstractBeanFactory.java
protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// BeanFactoryUtils.java
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        return name;
    }
    // 獲取 name 對應的 beanName,
    // 不為 null 則返回 `transformedBeanNameCache` 緩存中對應的 beanName,
    // 為 null 則對 name 進行處理,將前綴 '&' 去除,直至沒有 '&',然后放入 `transformedBeanNameCache` 緩存中,並返回處理后的 beanName
    return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
        do {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
        }
        while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
        return beanName;
    });
}
// SimpleAliasRegistry.java
public String canonicalName(String name) {
    String canonicalName = name;
    // Handle aliasing...
    String resolvedName;
    // 循環,從 aliasMap 中,獲取到最終的 beanName
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

過程並不復雜,先將前綴 & 去除(如果存在),如果是別名則獲取對應的 beanName

定義了一個 FactoryBean 類型的 Bean,名稱為 user,通過 user 獲取 Bean,獲取到的是 FactoryBean#getObject() 返回的對象(只會被調用一次)

通過 &user 獲取 Bean,獲取到的是 FactoryBean 本身這個對象

2. 從緩存中獲取單例 Bean

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
Object sharedInstance = getSingleton(beanName);

單例模式的 Bean 被創建后會緩存,為了避免循環依賴注入,在創建過程會臨時緩存正在創建的 Bean(早期 Bean),在后續文章會講到,從緩存中獲取對象過程如下:

// DefaultSingletonBeanRegistry.java

public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // <1> **【一級 Map】**從單例緩存 `singletonObjects` 中獲取 beanName 對應的 Bean
    Object singletonObject = this.singletonObjects.get(beanName);
    // <2> 如果**一級 Map**中不存在,且當前 beanName 正在創建
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // <2.1> 對 `singletonObjects` 加鎖
        synchronized (this.singletonObjects) {
            // <2.2> **【二級 Map】**從 `earlySingletonObjects` 集合中獲取,里面會保存從 **三級 Map** 獲取到的正在初始化的 Bean
            singletonObject = this.earlySingletonObjects.get(beanName);
            // <2.3> 如果**二級 Map** 中不存在,且允許提前創建
            if (singletonObject == null && allowEarlyReference) {
                // <2.3.1> **【三級 Map】**從 `singletonFactories` 中獲取對應的 ObjectFactory 實現類
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                // 如果從**三級 Map** 中存在對應的對象,則進行下面的處理
                if (singletonFactory != null) {
                    // <2.3.2> 調用 ObjectFactory#getOject() 方法,獲取目標 Bean 對象(早期半成品)
                    singletonObject = singletonFactory.getObject();
                    // <2.3.3> 將目標對象放入**二級 Map**
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    // <2.3.4> 從**三級 Map**移除 `beanName`
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    // <3> 返回從緩存中獲取的對象
    return singletonObject;
}

過程如下:

  1. 【一級 Map】從單例緩存 singletonObjects 中獲取 beanName 對應的 Bean
  2. 如果一級 Map中不存在,且當前 beanName 正在創建
    1. singletonObjects 加鎖
    2. 【二級 Map】earlySingletonObjects 集合中獲取,里面會保存從 三級 Map 獲取到的正在初始化的 Bean
    3. 如果二級 Map 中不存在,且允許提前創建
      1. 【三級 Map】singletonFactories 中獲取對應的 ObjectFactory 實現類,如果從三級 Map 中存在對應的對象,則進行下面的處理
      2. 調用 ObjectFactory#getOject() 方法,獲取目標 Bean 對象(早期半成品)
      3. 將目標對象放入二級 Map
      4. 三級 Map移除 beanName
  3. 返回從緩存中獲取的對象

這個過程對應《深入了解 Spring IoC(面試題)》中的BeanFactory 是如何處理循環依賴問題

3. FactoryBean 的處理

一般情況下,Spring 通過反射機制利用 Bean 的 beanClass 屬性指定實現類來實例化 Bean。某些情況下,Bean 的實例化過程比較復雜,如果按照傳統的方式,則需要提供大量的配置信息,配置方式的靈活性有限,這時采用編碼的方式可能會得到一個簡單的方案。Spring 為此提供了一個 FactoryBean 的工廠 Bean 接口,用戶可以通過實現該接口定制實例化 Bean 的邏輯。

FactoryBean 接口對於 Spring 框架本身也非常重要,其內部就提供了大量 FactoryBean 的實現。它們隱藏了實例化過程中一些復雜細節,給上層應用帶來了便利。

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

不管是從緩存中獲取的還是新創建的,都會調用這個方法進行處理,如果是 FactoryBean 類型則調用其 getObject() 獲取目標對象

getObjectForBeanInstance 方法

// AbstractBeanFactory.java
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, 
                                          @Nullable RootBeanDefinition mbd) {
    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    // <1> 若 `name` 以 `&` 開頭,說明想要獲取 FactoryBean,則校驗其**正確性**
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        // <1.1> 如果是 NullBean 空對象,則直接返回
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        // <1.2> 如果不是 FactoryBean 類型,則拋出異常
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
        }
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the caller actually wants a reference to the factory.
    // 到這里我們就有了一個 Bean,可能是一個正常的 Bean,也可能是一個 FactoryBean
    // 如果是 FactoryBean,則需要通過其 getObject() 方法獲取目標對象

    // <2> 如果 `beanInstance` 不是 FactoryBean 類型,不需要再處理則直接返回
    // 或者(表示是 FactoryBean 類型) `name` 以 `&` 開頭,表示你想要獲取實際 FactoryBean 對象,則直接返回
    // 還不符合條件的話,表示是 FactoryBean,需要獲取 getObject() 返回目標對象
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    // <3> 如果入參沒有傳 BeanDefinition,則從 `factoryBeanObjectCache` 緩存中獲取對應的 Bean 對象
	// 入參傳了 BeanDefinition 表示這個 Bean 是剛創建的,不走緩存,需要調用其 getObject() 方法獲取目標對象
	// `factoryBeanObjectCache`:FactoryBean#getObject() 調用一次后返回的目標對象緩存在這里
    if (mbd == null) {
        object = getCachedObjectForFactoryBean(beanName);
    }
    // <4> 若第 `3` 步獲取的對象為空,則需要調用 FactoryBean#getObject() 獲得對象
    if (object == null) {
        // Return bean instance from factory.
        // <4.1> 將 `beanInstance` 轉換成 FactoryBean 類型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // Caches object obtained from FactoryBean if it is a singleton.
        // <4.2> 如果入參沒有傳 BeanDefinition 並且當前容器存在對應的 BeanDefinition
        if (mbd == null && containsBeanDefinition(beanName)) {
            // 獲取對應的 RootBeanDefinition(合並后)
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 是否是用戶定義的(不是 Spring 創建解析出來的)
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        // <4.3> **【核心】**通過 FactoryBean 獲得目標對象,單例模式會緩存在 `factoryBeanObjectCache` 中
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

過程如下:

  1. name& 開頭,說明想要獲取 FactoryBean,則校驗其正確性

    1. 如果是 NullBean 空對象,則直接返回
    2. 如果不是 FactoryBean 類型,則拋出異常
  2. 如果 beanInstance 不是 FactoryBean 類型,不需要再處理則直接返回;或者(表示是 FactoryBean 類型) name& 開頭,表示你想要獲取實際 FactoryBean 對象,則直接返回;還不符合條件的話,表示是 FactoryBean,需要獲取 getObject() 返回目標對象,往下處理

  3. 如果入參沒有傳 BeanDefinition,則從 factoryBeanObjectCache 緩存中獲取對應的 Bean 對象,如下:

    // FactoryBeanRegistrySupport.java
    protected Object getCachedObjectForFactoryBean(String beanName) {
        return this.factoryBeanObjectCache.get(beanName);
    }
    

    factoryBeanObjectCache:FactoryBean#getObject() 調用一次后返回的目標對象緩存在這里

    入參傳了 BeanDefinition 表示這個 Bean 是剛創建的,不走緩存,需要調用其 getObject() 方法獲取目標對象

  4. 若第 3 步獲取的對象為空,則需要調用 FactoryBean#getObject() 獲得對象

    1. beanInstance 轉換成 FactoryBean 類型
    2. 如果入參沒有傳 BeanDefinition 並且當前容器存在對應的 BeanDefinition,則獲取對應的 RootBeanDefinition(合並后)
    3. 【核心】通過 FactoryBean 獲得目標對象,單例模式會緩存在 factoryBeanObjectCache 中,調用 getObjectFromFactoryBean(FactoryBean<?>, String, boolean) 方法

getObjectFromFactoryBean 方法

getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) 方法,獲取 FactoryBean 的目標對象,方法如下:

// FactoryBeanRegistrySupport.java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // <1> `factory` 為單例模式,且單例 Bean 緩存中存在 `beanName` 對應的 FactoryBean 對象
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) { // <1.1> 獲取單例鎖,保證安全
            // <1.2> 從 `factoryBeanObjectCache` 緩存中獲取 FactoryBean#getObject() 創建的目標對象
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                // <1.3> 則根據 `factory` 獲取目標對象,調用 FactoryBean#getObject() 方法
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                // <1.4> 這里再進行一次校驗,看是否在緩存中存在 FactoryBean 創建的目標對象,如果有則優先從緩存中獲取
                // 保證 FactoryBean#getObject() 只能被調用一次
                // 沒有的話,則對剛獲取到的目標對象進行接下來的處理
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                } else {
                    // <1.5> 是否需要后續處理,這個 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是
                    if (shouldPostProcess) {
                        // <1.5.1> 若該 FactoryBean 處於創建中,則直接返回這個目標對象,不進行接下來的處理過程
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        }
                        // <1.5.2> 前置處理,將 `beanName` 標志為正在創建
                        beforeSingletonCreation(beanName);
                        try {
                            // <1.5.3> 對通過 FactoryBean 獲取的目標對象進行后置處理
                            // 遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            // <1.5.4> 后置處理,將 `beanName` 標志為不在創建中
                            afterSingletonCreation(beanName);
                        }
                    }
                    // <1.6> 如果緩存中存在 `beanName` 對應的 FactoryBean 對象
                    // 上面不是判斷了嗎?也可能在上面的處理過程會有所變化,所以這里在做一層判斷
                    // 目的:緩存 FactoryBean 創建的目標對象,則需要保證 FactoryBean 本身這個對象存在緩存中
                    if (containsSingleton(beanName)) {
                        // <1.6.1> 將這個 FactoryBean 創建的目標對象保存至 `factoryBeanObjectCache`
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            // <1.7> 返回 FactoryBean 創建的目標對象
            return object;
        }
    }
    // <2> `factory` 非單例模式,或單例 Bean 緩存中不存在 `beanName` 對應的 FactoryBean 對象
    else {
        // <2.1> 則根據 `factory` 獲取目標對象,調用 FactoryBean#getObject() 方法
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        // <2.2> 是否需要后續處理,這個 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是
        if (shouldPostProcess) {
            try {
                // <2.2.1> 對通過 FactoryBean 獲取的目標對象進行后置處理
                // 遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        // <2.3> 返回 FactoryBean 創建的目標對象,非單例模式不會進行緩存
        return object;
    }
}

過程如下:

  1. factory 為單例模式,且單例 Bean 緩存中存在 beanName 對應的 FactoryBean 對象

    1. 獲取單例鎖,保證安全

    2. factoryBeanObjectCache 緩存中獲取 FactoryBean#getObject() 創建的目標對象

    3. 則根據 factory 獲取目標對象,調用 FactoryBean#getObject() 方法(反射機制)

    4. 這里再進行一次校驗(第 1.2 已經判斷過),看是否在緩存中存在 FactoryBean 創建的目標對象,如果有則優先從緩存中獲取,保證 FactoryBean#getObject() 只能被調用一次;沒有的話,則對剛獲取到的目標對象進行接下來的處理

    5. 是否需要后續處理,這個 FactoryBean 的 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是

      1. 若該 FactoryBean 處於創建中,則直接返回這個目標對象,不進行接下來的處理過程

      2. 前置處理,將 beanName 標志為正在創建

      3. 對通過 FactoryBean 獲取的目標對象進行后置處理,遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)

      4. 后置處理,將 beanName 標志為不在創建中

      5. 如果緩存中存在 beanName 對應的 FactoryBean 對象,上面不是判斷了嗎(第 1 步判斷過)?

        也可能在上面的處理過程會有所變化,所以這里在做一層判斷,目的:緩存 FactoryBean 創建的目標對象,則需要保證 FactoryBean 本身這個對象存在緩存中

        1. 將這個 FactoryBean 創建的目標對象保存至 factoryBeanObjectCache
      6. 返回 FactoryBean 創建的目標對象

  2. factory 非單例模式,或單例 Bean 緩存中不存在 beanName 對應的 FactoryBean 對象

    1. 則根據 factory 獲取目標對象,調用 FactoryBean#getObject() 方法(反射機制)
    2. 是否需要后續處理,這個 FactoryBean 的 BeanDefinition 是否由 Spring 解析出來的,通常情況下都是
      1. 對通過 FactoryBean 獲取的目標對象進行后置處理,遍歷所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的處理)
    3. 返回 FactoryBean 創建的目標對象,非單例模式不會進行緩存

概括:調用 FactoryBean#getObject() 獲取目標對象,單例模式會緩存起來;過程中 Sping 考慮到各種情況,例如保證單例模式下 FactoryBean#getObject() 只調用一次,是否需要進行后置處理。

4. 非單例模式依賴檢查

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    return (curVal != null && (curVal.equals(beanName) // 相等
            || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); // 包含
}

prototypesCurrentlyInCreation 中保存非單例模式下正在創建的 Bean 的名稱,這里又重新創建,表示出現循環依賴,則直接拋出異常

Spring 對於非單例模式的 Bean 無法進行相關緩存,也就無法處理循環依賴的情況,選擇了直接拋出異常

5. BeanFactory 層次性加載 Bean 策略

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
BeanFactory parentBeanFactory = getParentBeanFactory();
// <5> 如果從當前容器中沒有找到對應的 BeanDefinition,則從父容器中加載(如果存在父容器)
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // Not found -> check parent.
    // <5.1> 獲取 `beanName`,因為可能是別名,則進行處理
    // 和第 `1` 步不同,不需要對 `&` 進行處理,因為進入父容器重新依賴查找
    String nameToLookup = originalBeanName(name);
    // <5.2> 若為 AbstractBeanFactory 類型,委托父容器的 doGetBean 方法進行處理
    // 否則,就是非 Spring IoC 容器,根據參數調用相應的 `getBean(...)`方法
    if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
    }
    else if (args != null) {
        return (T) parentBeanFactory.getBean(nameToLookup, args);
    }
    else if (requiredType != null) {
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
    else {
        return (T) parentBeanFactory.getBean(nameToLookup);
    }
}

如果當前 BeanFactory 沒有對應的 BeanDefinition,也就無法創建 Bean,但是如果存在 BeanFactory,則將接下來的操作交由 BeanFactory,找不到會層層找上去,如果所有 BeanFactory 都找不到對應的 BeanDefinition 最終會拋出異常。

6. 將 beanName 標記為已創建

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
// <6> 如果不是僅僅做類型檢查,則表示需要創建 Bean,將 `beanName` 標記為已創建過
if (!typeCheckOnly) {
    markBeanAsCreated(beanName);
}

如果不是僅僅做類型檢查,則調用 markBeanAsCreated(String beanName) 方法,如下:

// AbstractBeanFactory.java
protected void markBeanAsCreated(String beanName) {
    // 沒有創建
    if (!this.alreadyCreated.contains(beanName)) {
        // 加上全局鎖
        synchronized (this.mergedBeanDefinitions) {
            // 再次檢查一次:DCL 雙檢查模式
            if (!this.alreadyCreated.contains(beanName)) {
                // Let the bean definition get re-merged now that we're actually creating
                // the bean... just in case some of its metadata changed in the meantime.
                // 從 mergedBeanDefinitions 中刪除 beanName,並在下次訪問時重新創建它
                clearMergedBeanDefinition(beanName);
                // 添加到已創建 bean 集合中
                this.alreadyCreated.add(beanName);
            }
        }
    }
}

將這個 beanName 保存在 alreadyCreated 集合中(SetFromMap),在后面的循環依賴檢查中會使用到

7. 獲取 RootBeanDefinition

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
// <7> 從容器中獲取 `beanName` 對應的的 RootBeanDefinition(合並后)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 檢查是否為抽象類
checkMergedBeanDefinition(mbd, beanName, args);

因為我們定義的 Bean 大多數都被 Spring 解析成 GenericBeanDefinition 類型,具有父子關系,則需要獲取最終的 BeanDefinition;如果存在父子關系,則會進行一系列的合並,轉換成 RootBeanDefinition 對象,調用 getMergedLocalBeanDefinition(String beanName) 方法,如下:

// AbstractBeanFactory.java
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // Quick check on the concurrent map first, with minimal locking.
    // 從 `mergedBeanDefinitions` 緩存中獲取合並后的 RootBeanDefinition,存在則直接返回
    RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    if (mbd != null) {
        return mbd;
    }
    // 獲取 BeanDefinition 並轉換成,如果存在父子關系則進行合並
    return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
        throws BeanDefinitionStoreException {
    return getMergedBeanDefinition(beanName, bd, null);
}

protected RootBeanDefinition getMergedBeanDefinition(
        String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
        throws BeanDefinitionStoreException {

    // 加鎖
    synchronized (this.mergedBeanDefinitions) {
        RootBeanDefinition mbd = null;

        // Check with full lock now in order to enforce the same merged instance.
        if (containingBd == null) {
            mbd = this.mergedBeanDefinitions.get(beanName);
        }

        if (mbd == null) {
            // 如果沒有父類則直接轉換成 RootBeanDefinition 對象
            if (bd.getParentName() == null) {
                // Use copy of given root bean definition.
                if (bd instanceof RootBeanDefinition) {
                    mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                }
                else {
                    mbd = new RootBeanDefinition(bd);
                }
            }
            // 有父類則進行合並
            else {
                // Child bean definition: needs to be merged with parent.
                BeanDefinition pbd;
                try {
                    // 獲取父類的對應的 BeanDefinition 對象
                    String parentBeanName = transformedBeanName(bd.getParentName());
                    if (!beanName.equals(parentBeanName)) {
                        pbd = getMergedBeanDefinition(parentBeanName);
                    }
                    else {
                        BeanFactory parent = getParentBeanFactory();
                        if (parent instanceof ConfigurableBeanFactory) {
                            pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                        }
                        else {
                            throw new NoSuchBeanDefinitionException(parentBeanName,
                                    "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                    "': cannot be resolved without an AbstractBeanFactory parent");
                        }
                    }
                }
                catch (NoSuchBeanDefinitionException ex) {
                    throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                            "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                }
                // Deep copy with overridden values.
                mbd = new RootBeanDefinition(pbd);
                // 父子合並
                mbd.overrideFrom(bd);
            }

            // Set default singleton scope, if not configured before.
            if (!StringUtils.hasLength(mbd.getScope())) {
                mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
            }

            // A bean contained in a non-singleton bean cannot be a singleton itself.
            // Let's correct this on the fly here, since this might be the result of
            // parent-child merging for the outer bean, in which case the original inner bean
            // definition will not have inherited the merged outer bean's singleton status.
            if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                mbd.setScope(containingBd.getScope());
            }

            // Cache the merged bean definition for the time being
            // (it might still get re-merged later on in order to pick up metadata changes)
            if (containingBd == null && isCacheBeanMetadata()) {
                // 放入緩存中
                this.mergedBeanDefinitions.put(beanName, mbd);
            }
        }

        return mbd;
    }
}

過程大致如下:

  1. mergedBeanDefinitions 緩存中獲取合並后的 RootBeanDefinition,存在則直接返回,不存在則進行后面的操作
  2. 獲取合並后的 RootBeanDefinition 對象,邏輯並不復雜,將一些屬性進行合並;這里對於 BeanDefinition 的獲取也存在層次性查找策略;注意,如果一個單例 BeanDefinition 包含在非單例 BeanDefinition,那么會變成非單例 Bean

后續還會對合並后的 RootBeanDefinition 對象進行檢查,如果是抽象的,則拋出異常

8. 依賴 Bean 的處理

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
// Guarantee initialization of beans that the current bean depends on.
// <8> 獲取當前正在創建的 Bean 所依賴對象集合(`depends-on` 配置的依賴)
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
    for (String dep : dependsOn) {
        // <8.1> 檢測是否存在循環依賴,存在則拋出異常
        if (isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
        }
        // <8.2> 將 `beanName` 與 `dep` 之間依賴的關系進行緩存
        registerDependentBean(dep, beanName);
        try {
            // <8.3> 先創建好依賴的 Bean(重新調用 `getBean(...)` 方法)
            getBean(dep);
        }
        catch (NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
    }
}
  • 每個 Bean 不一定是單獨工作的,可以通過 depends-on 配置依賴的 Bean,其他 Bean 也可以依賴它

  • 對於依賴的 Bean,會優先加載,所以在 Spring 的加載順序中,在初始化某個 Bean 的時候,首先會初始化這個 Bean 的依賴

isDependent 方法

在初始化依賴的 Bean 之前,會調用 isDependent(String beanName, String dependentBeanName) 方法,判斷是否出現循環依賴,方法如下:

DefaultSingletonBeanRegistry.java
protected boolean isDependent(String beanName, String dependentBeanName) {
    synchronized (this.dependentBeanMap) {
        return isDependent(beanName, dependentBeanName, null);
    }
}

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
    // <1> `alreadySeen` 中已經檢測過該 `beanName` 則直接返回 `false`
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    // <2> 獲取最終的 `beanName`,因為可能是別名,需要進行相關處理
    String canonicalName = canonicalName(beanName);
    // <3> 從 `dependentBeanMap` 中獲取依賴 `beanName` 的 Bean 集合
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    // <4> 沒有 Bean 依賴該 `beanName`,也就不存在循環依賴,返回 `false`
    if (dependentBeans == null) {
        return false;
    }
    // <5> 依賴 `beanName` 的 Bean 們包含 `dependentBeanName`,表示出現循環依賴,返回 `true`
    if (dependentBeans.contains(dependentBeanName)) {
        // `beanName` 與 `dependentBeanName` 相互依賴
        return true;
    }
    // <6> 對依賴該 `beanName` 的 Bean 們進行檢查,看它們是否與 `dependentBeanName` 存在依賴,遞歸處理
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<>();
        }
        alreadySeen.add(beanName);
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

過程大致如下:

  1. alreadySeen 中已經檢測過該 beanName 則直接返回 false
  2. 獲取最終的 beanName,因為可能是別名,需要進行相關處理
  3. dependentBeanMap 中獲取依賴 beanName 的 Bean 集合
  4. 沒有 Bean 依賴該 beanName,也就不存在循環依賴,返回 false
  5. 依賴 beanName 的 Bean 們包含 dependentBeanName,表示出現循環依賴,返回 true
  6. 對依賴該 beanName 的 Bean 們進行檢查,看它們是否與 dependentBeanName 存在依賴,遞歸處理

判斷是否出現循環依賴的過程有點繞,需要花點時間理解一下。例如:現在檢查 A ->(依賴)B,看是否出現循環依賴,我獲取到依賴 A 的所有 Bean,看 B 是否依賴這里面的 Bean,如果出現 A -> B -> C -> A,那就出現循環依賴了。如果出現循環依賴,則會拋出異常,所以我們說 Spring 處理了單例 Bean 的循環依賴注入比較好一點。

registerDependentBean 方法

beanNamedepbeanName 的依賴)之間依賴的關系進行緩存,調用 registerDependentBean(String beanName, String dependentBeanName) 方法,如下:

DefaultSingletonBeanRegistry.java
public void registerDependentBean(String beanName, String dependentBeanName) {
    String canonicalName = canonicalName(beanName);

    // 對應關系:beanName -> 依賴 beanName 的集合
    synchronized (this.dependentBeanMap) {
        Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, 
                                                                           k -> new LinkedHashSet<>(8));
        if (!dependentBeans.add(dependentBeanName)) {
            return;
        }
    }

    // 對應關系:beanName - > beanName 的依賴的集合
    synchronized (this.dependenciesForBeanMap) {
        Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, 
                                                                                      k -> new LinkedHashSet<>(8));
        dependenciesForBean.add(canonicalName);
    }
}

將兩者的依賴關系保存起來,目的是在 isDependent 方法中判斷是否出現循環依賴

getBean 方法

加載 beanName 依賴的 Bean,同樣是調用 AbstractBeanFactory#getBean(String dep) 方法,也就是本文開頭講的這個方法

9. 不同作用域的 Bean 的創建

Spring 的作用域划分為三種:單例模式、原型模式、其他模式,會依次進行判斷,然后進行創建,創建過程都是一樣的,主要是存儲范圍不一樣

  • 單例模式:一個 BeanFactory 有且僅有一個實例
  • 原型模式:每次依賴查找和依賴注入生成新 Bean 對象
  • 其他模式,例如 request 作用域會將 Bean 存儲在 ServletRequest 上下文中;session 作用域會將 Bean 存儲在 HttpSession 中;application 作用域會將 Bean 存儲在 ServletContext 中

單例模式

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
if (mbd.isSingleton()) { // <9.1> 單例模式
    /*
     * <9.1.1> 創建 Bean,成功創建則進行緩存,並移除緩存的早期對象
     * 創建過程實際調用的下面這個 `createBean(...)` 方法
     */
    sharedInstance = getSingleton(beanName,
            // ObjectFactory 實現類
            () -> {
                try {
                    // **【核心】** 創建 Bean
                    return createBean(beanName, mbd, args);
                } catch (BeansException ex) {
                    // Explicitly remove instance from singleton cache: It might have been put there
                    // eagerly by the creation process, to allow for circular reference resolution.
                    // Also remove any beans that received a temporary reference to the bean.
                    // 如果創建過程出現異常,則顯式地從緩存中刪除當前 Bean 相關信息
                    // 在單例模式下為了解決循環依賴,創建過程會緩存早期對象,這里需要進行刪除
                    destroySingleton(beanName);
                    throw ex;
                }
    });
    // <9.1.2> 獲取 Bean 的目標對象,`scopedInstance` 非 FactoryBean 類型直接返回
    // 否則,調用 FactoryBean#getObject() 獲取目標對象
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

如果是單例模式,創建過程大致如下:

  1. 調用 DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法

    創建 Bean,成功創建則進行緩存,並移除緩存的早期對象,創建過程實際調用的下面這個 AbstractAutowireCapableBeanFactory#createBean(...) 方法

  2. FactoryBean 的處理,在前面 3. FactoryBean 的處理 中已經分析過

getSingleton 方法

DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法,單例模式下獲取單例 Bean,如下:

// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    // 全局加鎖
    synchronized (this.singletonObjects) {
        // <1> 從 `singletonObjects` 單例 Bean 的緩存中獲取 Bean(再檢查一遍),存在則直接返回,否則開始創建
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            // <2> 將 `beanName` 標記為單例模式正在創建
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                /**
                 * <3> 創建 Bean,實際調用 
                 * {@link AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])} 方法
                 */
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // <4> 將 `beanName` 標記為不在創建中,照應第 `2` 步
                afterSingletonCreation(beanName);
            }
            // <5> 如果這里是新創建的單例模式 Bean,則在 `singletonObjects` 中進行緩存(無序),移除緩存的早期對象
            // 並在 `registeredSingletons` 中保存 `beanName`,保證注冊順序
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

過程大致如下:

  1. singletonObjects 單例 Bean 的緩存中獲取 Bean(再檢查一遍),存在則直接返回,否則開始創建
  2. beanName 標記為單例模式正在創建
  3. 【核心】創建 Bean,實際調用 AbstractAutowireCapableBeanFactory#createBean(...) 方法
  4. beanName 標記為不在創建中,照應第 2
  5. 如果這里是新創建的單例模式 Bean,則在 singletonObjects 中進行緩存(無序),移除緩存的早期對象,並在 registeredSingletons 中保存 beanName,保證注冊順序
createBean 方法

AbstractAutowireCapableBeanFactory#createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法,創建 Bean,整個過程大致如下:

  1. Bean 的實例化
  2. 屬性賦值(包括依賴注入)
  3. Aware 接口回調
  4. 調用初始化方法

上面涉及到 Bean 生命周期的大部分階段,將會在后續的文章中依次分析

原型模式

對應代碼段:

// AbstractBeanFactory.java
// <9.2> 原型模式
else if (mbd.isPrototype()) {
    // It's a prototype -> create a new instance.
    Object prototypeInstance = null;
    try {
        // <9.2.1> 將 `beanName` 標記為**非單例模式**正在創建
        beforePrototypeCreation(beanName);
        // <9.2.2> **【核心】** 創建 Bean
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        // <9.2.3> 將 `beanName` 標記為不在創建中,照應第 `9.2.1` 步
        afterPrototypeCreation(beanName);
    }
    // <9.2.4> 獲取 Bean 的目標對象,`scopedInstance` 非 FactoryBean 類型直接返回
    // 否則,調用 FactoryBean#getObject() 獲取目標對象
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

過程大致如下:

  1. beanName 標記為非單例模式正在創建
  2. 【核心】創建 Bean 也是調用 AbstractAutowireCapableBeanFactory#createBean(...) 方法,這里沒有緩存,每次加載 Bean 都會創建一個對象
  3. beanName 標記為不在創建中,照應第 1
  4. FactoryBean 的處理,在前面 3. FactoryBean 的處理 中已經分析過

其他模式

對應代碼段:

// AbstractBeanFactory.java
// <9.3> 其他模式
else {
    // <9.3.1> 獲取該模式的 Scope 對象 `scope`,不存在則拋出異常
    String scopeName = mbd.getScope();
    final Scope scope = this.scopes.get(scopeName);
    if (scope == null) {
        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
    }
    try {
        // <9.3.2> 從 `scope` 中獲取 `beanName` 對應的對象(看你的具體實現),不存在則執行**原型模式**的四個步驟進行創建
        Object scopedInstance = scope.get(beanName, () -> {
            // 將 `beanName` 標記為**非單例模式**式正在創建
            beforePrototypeCreation(beanName);
            try {
                // **【核心】** 創建 Bean
                return createBean(beanName, mbd, args);
            }
            finally {
                // 將 `beanName` 標記為不在創建中,照應上一步
                afterPrototypeCreation(beanName);
            }
        });
        // 獲取 Bean 的目標對象,`scopedInstance` 非 FactoryBean 類型直接返回
        // 否則,調用 FactoryBean#getObject() 獲取目標對象
        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    }
    catch (IllegalStateException ex) {
        throw new BeanCreationException(beanName,
                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                ex);
    }
}

過程如下:

  1. 獲取該模式的 Scope 對象 scope,不存在則拋出異常
  2. scope 中獲取 beanName 對應的對象(看你的具體實現),不存在則執行原型模式的四個步驟進行創建

想要自定義一個作用域,可以實現 org.springframework.beans.factory.config.Scope 接口,並往 Spring 應用上下文注冊即可

10. 類型轉換

對應代碼段:

// AbstractBeanFactory#doGetBean(...) 方法
// <10> 如果入參 `requiredType` 不為空,並且 Bean 不是該類型,則需要進行類型轉換
if (requiredType != null && !requiredType.isInstance(bean)) {
    try {
        // <10.1> 通過類型轉換機制,將 Bean 轉換成 `requiredType` 類型
        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
        // <10.2> 轉換后的 Bean 為空則拋出異常
        if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
        // <10.3> 返回類型轉換后的 Bean 對象
        return convertedBean;
    }
    catch (TypeMismatchException ex) {
        if (logger.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                    ClassUtils.getQualifiedName(requiredType) + "'", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    }
}

如果入參 requiredType 不為空,並且 Bean 不是該類型,則需要進行類型轉換,過程如下:

  1. 通過類型轉換機制,將 Bean 轉換成 requiredType 類型,對 Spring 的類型轉換機制感興趣的小伙伴可以自己研究,參考 org.springframework.core.convert.support.DefaultConversionService
  2. 轉換后的 Bean 為空則拋出異常
  3. 返回類型轉換后的 Bean 對象

總結

本文對 BeanFactory 接口的體系結構進行了分析,得知 DefaultListableBeanFactory 是 BeanFactory 的最底層實現,也就是 Spring 的底層 IoC 容器。接着分析了 AbstractBeanFactorygetBean(...) 方法,當我們顯示或者隱式地調用這個方法時,會觸發 Bean 的加載。上面所有小節對 Bean 的加載過程進行了分析,我已經有序地在每個小節面前添加了序號,這些序號對應着加載過程中的順序。

不同作用域的 Bean 的創建,底層都會調用 AbstractAutowireCapableBeanFactorycreateBean(...) 方法進行創建,創建 Bean 的過程涉及到 Bean 生命周期的大部分階段,例如實例化階段、屬性賦值階段、Aware 接口回調階段、初始化階段都是在這個方法中完成的,整個創建過程將在后續的文章進行分析。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM