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

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

Spring 版本:5.1.14.RELEASEjava

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

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

開啓 Bean 的加載

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

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

BeanFactory 體系結構

先來看看 BeanFactory 接口的繼承關係緩存

簡單描述這些接口:安全

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

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

  • 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 接口回調階段、初始化階段都是在這個方法中完成的,整個建立過程將在後續的文章進行分析。

相關文章
相關標籤/搜索