主頁 > 後端開發 > 死磕Spring之IoC篇 - Bean 的創建程序

死磕Spring之IoC篇 - Bean 的創建程序

2021-03-02 06:15:57 後端開發

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

Spring 版本:5.1.14.RELEASE

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

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

Bean 的創建程序

上一篇《開啟 Bean 的加載》文章分析了 Bean 的整個加載程序,當我們顯示或者隱式地呼叫AbstractBeanFactorygetBean(...) 方法時,會觸發 Bean 的加載,會進行一系列的處理,具體實作可查看上一篇文章,

對于不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactorycreateBean(...) 方法進行創建,創建 Bean 的程序涉及到 Bean 生命周期的大部分階段,例如實體化階段、屬性賦值階段、Aware 介面回呼階段、初始化階段都是在這個方法中完成的,這個核心方法在上一篇文章沒有講述,接下來將在本文進行分析,

AbstractAutowireCapableBeanFactory

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory 抽象類,繼承 AbstractBeanFactory,實作 AutowireCapableBeanFactory 介面,完成 Bean 的創建

【核心】createBean 方法

createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法,創建 Bean,方法如下:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {
    if (logger.isTraceEnabled()) {
        logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    // <1> 獲取 `mbd` 對應的 Class 物件,確保當前 Bean 能夠被創建出來
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    // 如果這里獲取到了 Class 物件,但是 `mbd` 中沒有 Class 物件的相關資訊,表示這個 Class 物件是動態決議出來的
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        // 復制一份 `mbd`,并設定 Class 物件,因為動態決議出來的 Class 物件不被共享
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // Prepare method overrides.
    try {
        // <2> 對所有的 MethodOverride 進行驗證和準備作業(確保存在對應的方法,并設定為不能重復加載)
        mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        /**
         * <3> 在實體化前進行相關處理,會先呼叫所有 {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}
         * 注意,如果這里回傳物件不是 `null` 的話,不會繼續往下執行原本初始化操作,直接回傳,也就是說這個方法回傳的是最終實體物件
         * 可以通過這種方式提前回傳一個代理物件,例如 AOP 的實作,或者 RPC 遠程呼叫的實作(因為本地類沒有遠程能力,可以通過這種方式進行攔截)
         */
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    } catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        // <4> 創建 Bean 物件 `beanInstance`,如果上一步沒有回傳代理物件,就只能走常規的路線進行 Bean 的創建了
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isTraceEnabled()) {
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        // <5> 將 `beanInstance` 回傳
        return beanInstance;
    } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        // A previously detected exception with proper bean creation context already,
        // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
        throw ex;
    } catch (Throwable ex) {
        throw new BeanCreationException(
                mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}

入參:

  • beanName:Bean 的名稱
  • mbd:Bean 的 BeanDefinition 物件(合并后)
  • args:創建 Bean 的引數,我們通常不會傳,所以這里為 null

程序大致如下:

  1. 獲取 mbd 對應的 Class 物件,確保當前 Bean 能夠被創建出來,呼叫 resolveBeanClass(...) 方法

  2. 對所有的 MethodOverride 進行驗證準備作業(確保存在對應的方法,并設定為不能重復加載)

  3. 實體化前階段在實體化前進行相關處理,會先呼叫所有 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

    注意,如果這里回傳物件不是 null 的話,不會繼續往下執行原本初始化操作,直接回傳,也就是說這個方法回傳的是最終實體物件

    可以通過這種方式提前回傳一個代理物件,例如 AOP 的實作,或者 RPC 遠程呼叫的實作(因為本地類沒有遠程能力,可以通過這種方式進行攔截)

  4. 創建 Bean 物件 beanInstance,如果上一步沒有回傳代理物件,就只能走常規的路線進行 Bean 的創建了,呼叫 doCreateBean(...) 方法

  5. beanInstance 回傳

可以看到這個方法中并沒有開始真正 Bean 的創建,在這個方法的第 4 步會呼叫 doCreateBean(...) 方法創建 Bean

【核心】doCreateBean 方法

doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args),創建 Bean,方法如下:

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

    // Instantiate the bean.
    /**
     * <1> Bean 的實體化階段,會將 Bean 的實體物件封裝成 {@link BeanWrapperImpl} 包裝物件
     * BeanWrapperImpl 承擔的角色:
     * 1. Bean 實體的包裝
     * 2. {@link org.springframework.beans.PropertyAccessor} 屬性編輯器
     * 3. {@link org.springframework.beans.PropertyEditorRegistry} 屬性編輯器注冊表
     * 4. {@link org.springframework.core.convert.ConversionService} 型別轉換器(Spring 3+,替換了之前的 TypeConverter)
     */
    BeanWrapper instanceWrapper = null;
    // <1.1> 如果是單例模式,則先嘗試從 `factoryBeanInstanceCache` 快取中獲取實體物件,并從快取中移除
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    // <1.2> 使用合適的實體化策略來創建 Bean 的實體:工廠方法、建構式自動注入、簡單初始化
    // 主要是將 BeanDefinition 轉換為 BeanWrapper 物件
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // <1.3> 獲取包裝的實體物件 `bean`
    final Object bean = instanceWrapper.getWrappedInstance();
    // <1.4> 獲取包裝的實體物件的型別 `beanType`
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    // <2> 對 RootBeanDefinition(合并后)進行加工處理
    synchronized (mbd.postProcessingLock) { // 加鎖,執行緒安全
        // <2.1> 如果該 RootBeanDefinition 沒有處理過,則進行下面的處理
        if (!mbd.postProcessed) {
            try {
                /**
                 * <2.2> 對 RootBeanDefinition(合并后)進行加工處理
                 * 呼叫所有 {@link MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition}
                 * 【重要】例如有下面兩個處理器:
                 * 1. AutowiredAnnotationBeanPostProcessor 會先決議出 @Autowired 和 @Value 注解標注的屬性的注入元資訊,后續進行依賴注入;
                 * 2. CommonAnnotationBeanPostProcessor 會先決議出 @Resource 注解標注的屬性的注入元資訊,后續進行依賴注入,
                 * 它也會找到 @PostConstruct 和 @PreDestroy 注解標注的方法,并構建一個 LifecycleMetadata 物件,用于后續生命周期中的初始化和銷毀
                 */
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            // <2.3> 設定該 RootBeanDefinition 被處理過,避免重復處理
            mbd.postProcessed = true;
        }
    }

    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    // <3> 提前暴露這個 `bean`,如果可以的話,目的是解決單例模式 Bean 的回圈依賴注入
    // <3.1> 判斷是否可以提前暴露
    boolean earlySingletonExposure = (mbd.isSingleton() // 單例模式
            && this.allowCircularReferences // 允許回圈依賴,默認為 true
            && isSingletonCurrentlyInCreation(beanName)); // 當前單例 bean 正在被創建,在前面已經標記過
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        /**
         * <3.2>
         * 創建一個 ObjectFactory 實作類,用于回傳當前正在被創建的 `bean`,提前暴露,保存在 `singletonFactories` (**三級 Map**)快取中
         *
         * 可以回到前面的 {@link AbstractBeanFactory#doGetBean#getSingleton(String)} 方法
         * 加載 Bean 的程序會先從快取中獲取單例 Bean,可以避免單例模式 Bean 回圈依賴注入的問題
         */
        addSingletonFactory(beanName,
                // ObjectFactory 實作類
                () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    // 開始初始化 `bean`
    Object exposedObject = bean;
    try {
        // <4> 對 `bean` 進行屬性填充,注入對應的屬性值
        populateBean(beanName, mbd, instanceWrapper);
        // <5> 初始化這個 `exposedObject`,呼叫其初始化方法
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
        else {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
        }
    }

    // <6> 回圈依賴注入的檢查
    if (earlySingletonExposure) {
        // <6.1> 獲取當前正在創建的 `beanName` 被依賴注入的早期參考
        // 注意,這里有一個入參是 `false`,不會呼叫上面第 `3` 步的 ObjectFactory 實作類
        // 也就是說當前 `bean` 如果出現回圈依賴注入,這里才能獲取到提前暴露的參考
        Object earlySingletonReference = getSingleton(beanName, false);
        // <6.2> 如果出現了回圈依賴注入,則進行接下來的檢查作業
        if (earlySingletonReference != null) {
            // <6.2.1> 如果 `exposedObject` 沒有在初始化階段中被改變,也就是沒有被增強
            // 則使用提前暴露的那個參考
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            // <6.2.2> 否則,`exposedObject` 已經不是被別的 Bean 依賴注入的那個 Bean
            else if (!this.allowRawInjectionDespiteWrapping // 是否允許注入未加工的 Bean,默認為 false,這里取非就為 true
                    && hasDependentBean(beanName)) { // 存在依賴 `beanName` 的 Bean(通過 `depends-on` 配置)
                // 獲取依賴當前 `beanName` 的 Bean 們的名稱(通過 `depends-on` 配置)
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                // 接下來進行判斷,如果依賴 `beanName` 的 Bean 已經創建
                // 說明當前 `beanName` 被注入了,而這里最終的 `bean` 被包裝過,不是之前被注入的
                // 則拋出例外
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(beanName,
                            "Bean with name '" + beanName + "' has been injected into other beans [" +
                            StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                            "] in its raw version as part of a circular reference, but has eventually been " +
                            "wrapped. This means that said other beans do not use the final version of the " +
                            "bean. This is often the result of over-eager type matching - consider using " +
                            "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        /**
         * <7> 為當前 `bean` 注冊 DisposableBeanAdapter(如果需要的話),用于 Bean 生命周期中的銷毀階段
         * 可以看到 {@link DefaultSingletonBeanRegistry#destroySingletons()} 方法
         */
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }
    // <8> 回傳創建好的 `exposedObject` 物件
    return exposedObject;
}

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

  1. Bean 的實體化階段,會將 Bean 的實體物件封裝成 BeanWrapperImpl 包裝物件

    1. 如果是單例模式,則先嘗試從 factoryBeanInstanceCache 快取中獲取實體物件,并從快取中移除

    2. 使用合適的實體化策略來創建 Bean 的實體:工廠方法、建構式自動注入、簡單初始化,主要是將 BeanDefinition 轉換為 BeanWrapper 物件

      呼叫 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法

    3. 獲取包裝的實體物件 bean

    4. 獲取包裝的實體物件的型別 beanType

  2. 對 RootBeanDefinition(合并后)進行加工處理

    1. 如果該 RootBeanDefinition 沒有處理過,則進行下面的處理
    2. 呼叫所有的 MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition,這個程序非常重要,例如 Spring 內有下面兩個處理器:
      • AutowiredAnnotationBeanPostProcessor,會先決議出 @Autowired@Value 注解標注的屬性的注入元資訊,后續進行依賴注入
      • CommonAnnotationBeanPostProcessor,會先決議出 @Resource 注解標注的屬性的注入元資訊,后續進行依賴注入,它也會找到 @PostConstruct@PreDestroy 注解標注的方法,并構建一個 LifecycleMetadata 物件,用于后續生命周期中的初始化和銷毀
    3. 設定該 RootBeanDefinition 被處理過,避免重復處理
  3. 提前暴露這個 bean,如果可以的話,目的是解決單例模式 Bean 的回圈依賴注入

    1. 判斷是否可以提前暴露,滿足三個條件:單例模式、允許回圈依賴(默認為 true)、當前單例 bean 正在被創建,在前面已經標記過
    2. 創建一個 ObjectFactory 實作類,用于回傳當前正在被創建的 bean,提前暴露,保存在 singletonFactories三級 Map)快取中

接下來開始初始化上面的 bean 實體物件,會先創建一個 Object exposedObject 等于 bean (參考)

  1. bean 進行屬性填充,注入對應的屬性值,呼叫 populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 方法
  2. 初始化這個 exposedObject,呼叫其初始化方法,呼叫 initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) 方法

  1. 回圈依賴注入的檢查

    1. 獲取當前正在創建的 beanName 被依賴注入的早期參考,呼叫 DefaultSingletonBeanRegistry#getSingleton(String beanName, boolean allowEarlyReference) 方法,注意,這里有一個入參是 false,不會呼叫上面第 3 步的 ObjectFactory 實作類,也就是說當前 bean 如果出現回圈依賴注入,這里才能獲取到提前暴露的參考
    2. 如果出現了回圈依賴注入,則進行接下來的檢查作業
      1. 如果 exposedObject 沒有在初始化階段中被改變,也就是沒有被增強,則使用提前暴露的那個參考
      2. 否則,exposedObject 已經不是被別的 Bean 依賴注入的那個 Bean,如果依賴當前 beanName 的 Bean(通過 depends-on 配置)已經被創建,則拋出例外
  2. 為當前 bean 注冊 DisposableBeanAdapter(如果需要的話),用于 Bean 生命周期中的銷毀階段

  3. 回傳創建好的 exposedObject 物件

概括:

  • 首先獲取對應的 Class 物件,創建一個實體物件
  • 對這個實體物件進行屬性填充
  • 呼叫這個實體物件的初始化方法

關于上面創建 Bean 的兩個方法的相關步驟沒有展開討論,下面會依次進行分析

1. 創建 Class 物件

對應代碼段:

// AbstractAutowireCapableBeanFactory#createBean(...) 方法
// <1> 獲取 `mbd` 對應的 Class 物件,確保當前 Bean 能夠被創建出來
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
// 如果這里獲取到了 Class 物件,但是 `mbd` 中沒有 Class 物件的相關資訊,表示這個 Class 物件是動態決議出來的
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    // 復制一份 `mbd`,并設定 Class 物件,因為動態決議出來的 Class 物件不被共享
    mbdToUse = new RootBeanDefinition(mbd);
    mbdToUse.setBeanClass(resolvedClass);
}

創建一個 Java 物件之前,需要確保存在對應的 Class 物件,如果這里獲取到了 Class 物件,但是 mbd 中沒有 Class 物件的相關資訊,表示這個 Class 物件是動態決議出來的,則需要復制一份 mbd,并設定 Class 物件,因為動態決議出來的 Class 物件不被共享

resolveBeanClass 方法

resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch),獲取 beanName 的 Class 物件,方法如下:

// AbstractBeanFactory.java
@Nullable
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
        throws CannotLoadBeanClassException {
    try {
        // 有 Class 物件則直接回傳
        if (mbd.hasBeanClass()) {
            return mbd.getBeanClass();
        }
        // 否則,呼叫 `doResolveBeanClass(...)` 方法,加載出一個 Class 物件
        if (System.getSecurityManager() != null) {
            return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () -> 
                                                 doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
        } else {
            return doResolveBeanClass(mbd, typesToMatch);
        }
    }
    // ... 省略 catch 各種例外
}

如果有 Class 物件則直接回傳,沒有的話呼叫 doResolveBeanClass(...) 方法去獲取 Class 物件

doResolveBeanClass 方法

// AbstractBeanFactory.java
@Nullable
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
        throws ClassNotFoundException {
    // 獲取 ClassLoader 加載器
    ClassLoader beanClassLoader = getBeanClassLoader();
    ClassLoader dynamicLoader = beanClassLoader;
    boolean freshResolve = false;

    if (!ObjectUtils.isEmpty(typesToMatch)) {
        // When just doing type checks (i.e. not creating an actual instance yet),
        // use the specified temporary class loader (e.g. in a weaving scenario).
        ClassLoader tempClassLoader = getTempClassLoader();
        if (tempClassLoader != null) {
            dynamicLoader = tempClassLoader;
            freshResolve = true;
            if (tempClassLoader instanceof DecoratingClassLoader) {
                DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                for (Class<?> typeToMatch : typesToMatch) {
                    dcl.excludeClass(typeToMatch.getName());
                }
            }
        }
    }

    // 獲取 `className`
    String className = mbd.getBeanClassName();
    if (className != null) {
        // 根據 BeanExpressionResolver 運算式處理器計算出 `className` 對應的結果
        // 可能還是一個類名稱,也可能是一個 Class 物件
        Object evaluated = evaluateBeanDefinitionString(className, mbd);
        if (!className.equals(evaluated)) {
            // A dynamically resolved expression, supported as of 4.2...
            if (evaluated instanceof Class) {
                return (Class<?>) evaluated;
            }
            else if (evaluated instanceof String) {
                className = (String) evaluated;
                freshResolve = true;
            }
            else {
                throw new IllegalStateException("Invalid class name expression result: " + evaluated);
            }
        }
        // 如果被處理過,則根據這個 `className` 創建一個 Class 物件
        // 創建的 Class 物件不會設定到 `mbd` 中
        if (freshResolve) {
            // When resolving against a temporary class loader, exit early in order
            // to avoid storing the resolved Class in the bean definition.
            if (dynamicLoader != null) {
                try {
                    return dynamicLoader.loadClass(className);
                }
                catch (ClassNotFoundException ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                    }
                }
            }
            return ClassUtils.forName(className, dynamicLoader);
        }
    }

    // Resolve regularly, caching the result in the BeanDefinition...
    // 讓 RootBeanDefinition 自己決議出 Class 物件
    return mbd.resolveBeanClass(beanClassLoader);
}

暫時忽略上面具體的每個細節,底層會根據 className 通過來加載器獲取對應的 Class 物件,并設定到 RootBeanDefinition

注意,這個程序可能是動態決議出來的,例如 className 是一個運算式,通過 BeanDefinition 運算式決議器決議出來的,然后根據其獲取 Class 物件,這里是不會設定到 RootBeanDefinition 中

2. MethodOverride 的驗證與準備

對應代碼段:

// AbstractAutowireCapableBeanFactory#createBean(...) 方法
try {
    // <2> 對所有的 MethodOverride 進行驗證和準備作業(確保存在對應的方法,并設定為不能重復加載)
    mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
    throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
}

<lookup-method /><replace-method /> 標簽會被決議成 LookupOverride 和 ReplaceOverride 物件,用于實作或覆寫某個方法,這里會進行驗證和準備作業,程序如下:

// AbstractBeanDefinition.java
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exist and determine their overloaded status.
    if (hasMethodOverrides()) { // 如果存在 `methodOverrides`
        // 獲取所有的 override method,遍歷進行處理
        getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
    }
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    if (count == 0) {
        throw new BeanDefinitionValidationException(
                "Invalid method override: no method with name '" + mo.getMethodName() +
                "' on class [" + getBeanClassName() + "]");
    }
    else if (count == 1) {
        // Mark override as not overloaded, to avoid the overhead of arg type checking.
        mo.setOverloaded(false);
    }
}

確保這個類中存在對應的方法,并設定為不能重復加載

3. 實體化前階段

對應代碼段:

// AbstractAutowireCapableBeanFactory#createBean(...) 方法
try {
    // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
    /**
     * <3> 在實體化前進行相關處理,會先呼叫所有 {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation}
     * 注意,如果這里回傳物件不是 `null` 的話,不會繼續往下執行原本初始化操作,直接回傳,也就是說這個方法回傳的是最終實體物件
     * 可以通過這種方式提前回傳一個代理物件,例如 AOP 的實作,或者 RPC 遠程呼叫的實作(因為本地類沒有遠程能力,可以通過這種方式進行攔截)
     */
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    if (bean != null) {
        return bean;
    }
}
catch (Throwable ex) {
    throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
}

在開始創建 Bean 執行,呼叫 resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) 方法進行處理,嘗試獲取一個代理物件

注意,如果這里回傳物件不是 null 的話,不會繼續往下執行原本初始化操作,直接回傳,也就是說這個方法回傳的是最終實體物件,可以通過這種方式提前回傳一個代理物件,例如 AOP 的實作,或者 RPC 遠程呼叫的實作(因為本地類沒有遠程能力,可以通過這種方式進行攔截)

resolveBeforeInstantiation 方法

// AbstractAutowireCapableBeanFactory.java
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        // 如果 RootBeanDefinition 不是用戶定義的(由 Spring 決議出來的),并且存在 InstantiationAwareBeanPostProcessor 處理器
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                 // 實體化前置處理
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 后置處理
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

如果 RootBeanDefinition 不是用戶定義的(由 Spring 決議出來的),并且存在 InstantiationAwareBeanPostProcessor 處理器,則進行下面的處理:

  1. 實體化前置處理,呼叫 applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) 方法,如下:

    @Nullable
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }
    

    遍歷所有的 InstantiationAwareBeanPostProcessor 處理器,執行 postProcessBeforeInstantiation 方法,實體化前置處理,如果有一個處理后回傳的結果不為空則直接回傳

  2. 如果第 1 步回傳的物件不為空,則呼叫 applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) 方法,如下:

    // AbstractAutowireCapableBeanFactory.java
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {
    
        Object result = existingBean;
        // 遍歷 BeanPostProcessor
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 處理
            Object current = processor.postProcessAfterInitialization(result, beanName);
            // 回傳空,則回傳 result
            if (current == null) {
                return result;
            }
            // 修改 result
            result = current;
        }
        return result;
    }
    

    遍歷所有的 BeanPostProcessor 處理器,執行 postProcessAfterInitialization 方法,初始化后置處理

4. Bean 的實體化

對應代碼段:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Instantiate the bean.
/**
 * <1> Bean 的實體化階段,會將 Bean 的實體物件封裝成 {@link BeanWrapperImpl} 包裝物件
 * BeanWrapperImpl 承擔的角色:
 * 1. Bean 實體的包裝
 * 2. {@link org.springframework.beans.PropertyAccessor} 屬性編輯器
 * 3. {@link org.springframework.beans.PropertyEditorRegistry} 屬性編輯器注冊表
 * 4. {@link org.springframework.core.convert.ConversionService} 型別轉換器(Spring 3+,替換了之前的 TypeConverter)
 */
BeanWrapper instanceWrapper = null;
// <1.1> 如果是單例模式,則先嘗試從 `factoryBeanInstanceCache` 快取中獲取實體物件,并從快取中移除
if (mbd.isSingleton()) {
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// <1.2> 使用合適的實體化策略來創建 Bean 的實體:工廠方法、建構式自動注入、簡單初始化
// 主要是將 BeanDefinition 轉換為 BeanWrapper 物件
if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// <1.3> 獲取包裝的實體物件 `bean`
final Object bean = instanceWrapper.getWrappedInstance();
// <1.4> 獲取包裝的實體物件的型別 `beanType`
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
    mbd.resolvedTargetType = beanType;
}

Bean 的實體化階段,會將 Bean 的實體物件封裝成 BeanWrapperImpl 包裝物件,BeanWrapperImpl 承擔的角色

  • Bean 實體的包裝
  • PropertyAccessor 屬性編輯器
  • PropertyEditorRegistry 屬性編輯器注冊表
  • ConversionService 型別轉換器(Spring 3+,替換了之前的 TypeConverter)

該程序大致如下

  1. 如果是單例模式,則先嘗試從 factoryBeanInstanceCache 快取中獲取實體物件,并從快取中移除
  2. 使用合適的實體化策略來創建 Bean 的實體:工廠方法、建構式自動注入、簡單初始化,主要是將 BeanDefinition 轉換為 BeanWrapper 物件,呼叫 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法
  3. 獲取包裝的實體物件 bean
  4. 獲取包裝的實體物件的型別 beanType

createBeanInstance 方法

createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法,創建一個 Bean 的實體物件,如下:

// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Make sure bean class is actually resolved at this point.
    // <1> 獲取 `beanName` 對應的 Class 物件
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    // <2> 如果存在 Supplier 實體化回呼介面,則使用給定的回呼方法創建一個實體物件
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // <3> 如果配置了 `factory-method` 工廠方法,則呼叫該方法來創建一個實體物件
    // 通過 @Bean 標注的方法會通過這里進行創建
    if (mbd.getFactoryMethodName() != null) {
        // 這個程序非常復雜,你可以理解為:
        // 找到最匹配的 Method 工廠方法,獲取相關引數(依賴注入),然后通過呼叫該方法回傳一個實體物件(反射機制)
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    // <4> 判斷這個 RootBeanDefinition 的構造方法是否已經被決議出來了
    // 因為找到最匹配的構造方法比較繁瑣,找到后會設定到 RootBeanDefinition 中,避免重復這個程序
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) { // 加鎖
            // <4.1> 構造方法已經決議出來了
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                // <4.2> 這個構造方法有入參,表示需要先獲取到對應的入參(構造器注入)
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }

    // <5> 如果最匹配的構造方法已決議出來
    if (resolved) {
        // <5.1> 如果這個構造方法有入參
        if (autowireNecessary) {
            // 這個程序很復雜,你可以理解為:
            // 找到最匹配的構造方法,這里會拿到已經被決議出來的這個方法,并找到入參(構造器注入),然后呼叫該方法回傳一個實體物件(反射機制)
            return autowireConstructor(beanName, mbd, null, null);
        }
        // <5.2> 否則,沒有入參
        else {
            // 直接呼叫決議出來構造方法,回傳一個實體物件(反射機制)
            return instantiateBean(beanName, mbd);
        }
    }

    // Candidate constructors for autowiring?
    // <6> 如果最匹配的構造方法還沒開始決議,那么需要找到一個最匹配的構造方法,然后創建一個實體物件

    /**
     * <6.1> 嘗試通過 SmartInstantiationAwareBeanPostProcessor 處理器的 determineCandidateConstructors 方法來找到一些合適的構造方法
     * 參考 {@link org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors}
     */
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    // <6.2> 是否滿足下面其中一個條件
    if (ctors != null // 上一步找到了合適的構造方法
            || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR // 構造器注入
            || mbd.hasConstructorArgumentValues() // 定義了構造方法的入參
            || !ObjectUtils.isEmpty(args)) // 當前方法指定了入參
    {
        // 找到最匹配的構造方法,如果 `ctors` 不為空,會從這里面找一個最匹配的,
        // 并找到入參(構造器注入),然后呼叫該方法回傳一個實體物件(反射機制)
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // Preferred constructors for default construction?
    /**
     * <7> 如果第 `6` 步還不滿足,那么嘗試獲取優先的構造方法
     * 參考 {@link org.springframework.context.support.GenericApplicationContext.ClassDerivedBeanDefinition}
     */
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        // 如果存在優先的構造方法,則從里面找到最匹配的一個,并找到入參(構造器注入),然后呼叫該方法回傳一個實體物件(反射機制)
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // No special handling: simply use no-arg constructor.
    // <8> 如果上面多種情況都不滿足,那只能使用兜底方法了,直接呼叫默認構造方法回傳一個實體物件(反射機制)
    return instantiateBean(beanName, mbd);
}

程序大致如下:

  1. 獲取 beanName 對應的 Class 物件

  2. 如果存在 Supplier 實體化回呼介面,則使用給定的回呼方法創建一個實體物件

  3. 如果配置了 factory-method 工廠方法,則呼叫該方法來創建一個實體物件,通過 @Bean 標注的方法會通過這里進行創建


如果上面兩種情況都不是,那么就進行接下來正常創建 Bean 實體的一個程序

  1. 判斷這個 RootBeanDefinition 的構造方法是否已經被決議出來了,因為找到最匹配的構造方法比較繁瑣,找到后會設定到 RootBeanDefinition 中,避免重復這個程序

    1. RootBeanDefinition 的 resolvedConstructorOrFactoryMethod 是否不為空,不為空表示構造方法已經決議出來了
    2. 構造方法已經決議出來了,則判斷它的 constructorArgumentsResolved 是否不為空,不為空表示有入參,需要先獲取到對應的入參(構造器注入)
  2. 如果最匹配的構造方法已決議出來

    1. 如果這個構造方法有入參,則找到最匹配的構造方法,這里會拿到已經被決議出來的這個方法,并找到入參(構造器注入),然后呼叫該方法回傳一個實體物件(反射機制)
    2. 否則,沒有入參,直接呼叫決議出來構造方法,回傳一個實體物件(反射機制)
  3. 如果最匹配的構造方法還沒開始決議,那么需要找到一個最匹配的構造方法,然后創建一個實體物件

    1. 先嘗試通過 SmartInstantiationAwareBeanPostProcessor 處理器找到一些合適的構造方法,保存在 ctors

    2. 是否滿足下面其中一個條件:ctors 不為空、構造器注入模式、定義了構造方法的入參、當前方法指定了入參,

      則找到最匹配的構造方法,如果 ctors 不為空,會從這里面找一個最匹配的,并找到入參(構造器注入),然后呼叫該方法回傳一個實體物件(反射機制)

  4. 如果第 6 步還不滿足,那么嘗試從 RootBeanDefinition 中獲取優先的構造方法

    1. 如果存在優先的構造方法,則從里面找到最匹配的一個,并找到入參(構造器注入),然后呼叫該方法回傳一個實體物件(反射機制)
  5. 如果上面多種情況都不滿足,那只能使用兜底方法了,直接呼叫默認構造方法回傳一個實體物件(反射機制)


整個的實體化程序非常的復雜,接下來進行概括:

  • 先拿到對應 Class 物件

  • 如果設定了 Supplier 實體化回呼介面,則通過該回呼介面獲取實體物件

  • 如果配置了通過 factory-method 工廠方法獲取實體物件,則通過這個方法創建實體物件,@Bean 標注的方法也是通過這里創建實體物件,方法入參會依賴注入

  • 找到最匹配的一個構造方法,并找到對應的入參(構造器注入),通過呼叫該方法回傳一個實體物件

  • 兜底方法,呼叫默認構造方法創建一個實體物件

因為整個程序比較繁瑣,涉及到的方法行數比較多,所以另起一篇《Bean 的實體化階段》文章進行分析

5. 對 RootBeanDefinition 加工處理

對應代碼段:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Allow post-processors to modify the merged bean definition.
// <2> 對 RootBeanDefinition(合并后)進行加工處理
synchronized (mbd.postProcessingLock) { // 加鎖,執行緒安全
    // <2.1> 如果該 RootBeanDefinition 沒有處理過,則進行下面的處理
    if (!mbd.postProcessed) {
        try {
            /**
             * <2.2> 對 RootBeanDefinition(合并后)進行加工處理
             * 呼叫所有 {@link MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition}
             * 【重要】例如有下面兩個處理器:
             * 1. AutowiredAnnotationBeanPostProcessor 會先決議出 @Autowired 和 @Value 注解標注的屬性的注入元資訊,后續進行依賴注入;
             * 2. CommonAnnotationBeanPostProcessor 會先決議出 @Resource 注解標注的屬性的注入元資訊,后續進行依賴注入,
             * 它也會找到 @PostConstruct 和 @PreDestroy 注解標注的方法,并構建一個 LifecycleMetadata 物件,用于后續生命周期中的初始化和銷毀
             */
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Post-processing of merged bean definition failed", ex);
        }
        // <2.3> 設定該 RootBeanDefinition 被處理過,避免重復處理
        mbd.postProcessed = true;
    }
}

在創建好實體物件后,允許你通過 MergedBeanDefinitionPostProcessor 處理器對該 RootBeanDefinition 進行加工處理,也可以從中獲取相關資訊

  1. 如果該 RootBeanDefinition 沒有加工處理過,則進行下面的處理,否則忽略該程序

  2. 對 RootBeanDefinition(合并后)進行加工處理,呼叫 applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) 方法,如下:

    // AbstractAutowireCapableBeanFactory.java
    protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
    }
    

    呼叫所有 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 方法對 RootBeanDefinition 進行加工處理,例如:AutowiredAnnotationBeanPostProcessor 會先決議出 @Autowired@Value 注解標注的屬性的注入元資訊,后續進行依賴注入;CommonAnnotationBeanPostProcessor 會先決議出 @Resource 注解標注的屬性的注入元資訊,后續進行依賴注入,它也會找到 @PostConstruct@PreDestroy 注解標注的方法,并構建一個 LifecycleMetadata 物件,用于后續生命周期中的初始化和銷毀

  3. 設定該 RootBeanDefinition 被處理過,避免重復處理

這個程序在后續講通過 @Autowired 依賴注入的實作原理會被提到

6. 提前暴露當前 Bean

對應代碼段:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// <3> 提前暴露這個 `bean`,如果可以的話,目的是解決單例模式 Bean 的回圈依賴注入
// <3.1> 判斷是否可以提前暴露
boolean earlySingletonExposure = (mbd.isSingleton() // 單例模式
        && this.allowCircularReferences // 允許回圈依賴,默認為 true
        && isSingletonCurrentlyInCreation(beanName)); // 當前單例 bean 正在被創建,在前面已經標記過
if (earlySingletonExposure) {
    if (logger.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
    }
    /**
     * <3.2>
     * 創建一個 ObjectFactory 實作類,用于回傳當前正在被創建的 `bean`,提前暴露,保存在 `singletonFactories` (**三級 Map**)快取中
     *
     * 可以回到前面的 {@link AbstractBeanFactory#doGetBean#getSingleton(String)} 方法
     * 加載 Bean 的程序會先從快取中獲取單例 Bean,可以避免單例模式 Bean 回圈依賴注入的問題
     */
    addSingletonFactory(beanName,
            // ObjectFactory 實作類
            () -> getEarlyBeanReference(beanName, mbd, bean));
}

在創建好實體物件后,此時還沒有進行屬性的填充和初始化等作業,先判斷是否可以提前暴露這個實體物件,目的是解決單例模式 Bean 的回圈依賴注入

  1. 判斷是否可以提前暴露,滿足這些條件:單例模式、允許回圈依賴(默認為 true)、當前單例 Bean 正在被創建(前面已經標記過)

  2. 如果可以的話,先通過 Lambda 運算式創建一個 ObjectFactory 實作類,如下:

    // AbstractAutowireCapableBeanFactory.java
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() // RootBeanDefinition 不是用戶定義的(由 Spring 決議出來的)
            && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }
    

    入參 bean 為當前 Bean 的實體物件(未初始化),這個實作類允許通過 SmartInstantiationAwareBeanPostProcessor 對這個提前暴露的物件進行處理,最侄訓回傳這個提前暴露的物件

  3. 然后呼叫 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) 方法,如下:

    // DefaultSingletonBeanRegistry.java
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }
    

    可以看到會往 singletonFactories 集合(三級 Map)中添加當前 beanNamesingletonFactory(ObjectFactory 實作類)的映射關系;

    earlySingletonObjects 集合(二級 Map)中移除當前 beanName

    registeredSingletons 集合(已注冊的 Bean 的名稱集合)中添加當前 beanName

可以回到《開啟 Bean 的加載》文章中2. 從快取中獲取單例 Bean小節,當這個 Bean 出現回圈依賴注入了,是不是可以避免相關問題,因為可以通過這個 ObjectFactory 實作類獲取到提前暴露的物件

因為回圈依賴注入的處理貫穿整個 Bean 的加載程序,所以另起一篇《單例 Bean 的回圈依賴處理》文章進行分析

7. 屬性填充

對應代碼段:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Initialize the bean instance.
// 開始初始化 `bean`
Object exposedObject = bean;
try {
    // <4> 對 `bean` 進行屬性填充,注入對應的屬性值
    populateBean(beanName, mbd, instanceWrapper);
    // <5> 初始化這個 `exposedObject`,呼叫其初始化方法
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
    }
    else {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    }
}

在創建好實體物件后,這個物件的屬性還沒有賦值,所以將這個實體物件的相關屬性進行賦值,也就是上面的第 <4>

populateBean 方法

populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) 方法,屬性填充,如下:

// AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // <1> 如果實體物件為空,則進行下面的判斷
    if (bw == null) {
        // <1.1> 這個 Bean 有屬性,則拋出例外
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        // <1.2> 否則,不用屬性填充,直接 `return`
        else {
            // Skip property population phase for null instance.
            return;
        }
    }

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    // <2> 實體化階段的后置處理,如果滿足這兩個條件
    if (!mbd.isSynthetic() // RootBeanDefinition 不是用戶定義的(由 Spring 決議出來的)
            && hasInstantiationAwareBeanPostProcessors()) { // 是否有 InstantiationAwareBeanPostProcessor 處理器
        // <2.1> 遍歷所有的 BeanPostProcessor
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 如果為 InstantiationAwareBeanPostProcessor 型別
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // <2.2> 對實體化物件進行后置處理
                // 注意如果回傳 false,直接 `return`,不會呼叫后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }
    }

    // <3> 獲取 `pvs`,承載當前物件的屬性值
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    // <4> 獲取這個 Bean 的注入模式,默認為 **AUTOWIRE_NO**,例如可以通過 `@Bean` 注解的 `autowire` 屬性配置注入模式
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    // <4.1> 如果注入模式為 **AUTOWIRE_BY_NAME** 或者 **AUTOWIRE_BY_TYPE**,則通過下面的方式獲取屬性值
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        // <4.2> 將 `pvs` 封裝成 MutablePropertyValues 物件 `newPvs`(允許對屬性進行相關操作)
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        // <4.3> **AUTOWIRE_BY_NAME** 模式,通過名稱獲取相關屬性值,保存在 `newPvs` 中
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        // <4.4> **AUTOWIRE_BY_TYPE** 模式,通過型別獲取相關屬性值,保存在 `newPvs` 中
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        // <4.5> 將 `newPvs` 復制給 `pvs`
        pvs = newPvs;
    }

    // 是否有 InstantiationAwareBeanPostProcessor 處理器
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    // 是否需要進行依賴檢查,默認為 true
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    PropertyDescriptor[] filteredPds = null;
    // <5> 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 `pvs` 進行處理
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }

        // <5.1> 遍歷所有的 BeanPostProcessor
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 如果為 InstantiationAwareBeanPostProcessor 型別
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                /**
                 * Spring 內部的 InstantiationAwareBeanPostProcessor 處理器:
                 * {@link AutowiredAnnotationBeanPostProcessor#postProcessProperties} 會決議 @Autowired 和 @Value 注解標注的屬性,獲取對應屬性值;
                 * {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties} 會 決議 Resource 注解標注的屬性,獲取對應的屬性值
                 */
                // <5.2> 呼叫處理器的 `postProcessProperties(...)` 方法,對 `pvs` 進行后置處理
                PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                // <5.3> 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要兼容老版本
                if (pvsToUse == null) {
                    // <5.3.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊)
                    if (filteredPds == null) {
                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                    }
                    // <5.3.2> 呼叫處理器的 `postProcessPropertyValues(...)` 方法,對 `pvs` 進行后置處理
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    // <5.3.3> 如果處理后的 PropertyValues 物件為空,直接 `return`,則不會呼叫后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充
                    if (pvsToUse == null) {
                        return;
                    }
                }
                // <5.4> 將處理后的 `pvsToUse` 復制給 `pvs`
                pvs = pvsToUse;
            }
        }
    }
    // <6> 依賴檢查
    if (needsDepCheck) {
        // <6.1> 找到這個 Bean 的所有 `java.beans.PropertyDescriptor` 屬性描述器(包含這個屬性的所有資訊)
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        // <6.2> 依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行拋出例外(默認不會)
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    // <7> 如果 `pvs` 不為空,則將里面的屬性值設定到當前 Bean 對應的屬性中(依賴注入)
    // 前面找到的屬性值并沒有設定到 Bean 中,且屬性值可能是一個運算式,型別也可能也不對,需要先進行處理和型別轉換,然后再設定到該實體物件中
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

程序大致如下:

  1. 如果實體物件為null,則進行下面的判斷

    1. 這個 Bean 有屬性,則拋出例外
    2. 否則,不用屬性填充,直接 return
  2. 實體化階段的后置處理,如果滿足這兩個條件:RootBeanDefinition 不是用戶定義的(由 Spring 決議出來的)、是否有 InstantiationAwareBeanPostProcessor 處理器

    1. 遍歷所有的 BeanPostProcessor

    2. 如果為 InstantiationAwareBeanPostProcessor 型別,則對實體化物件進行后置處理

      注意,如果回傳 false,直接 return,不會呼叫后面的 InstantiationAwareBeanPostProcessor 處理器,也不會進行接下來的屬性填充

  3. 獲取 pvs,承載當前物件的屬性值

  4. 獲取這個 Bean 的注入模式,默認為 AUTOWIRE_NO,例如可以通過 @Bean 注解的 autowire 屬性配置注入模式

    1. 如果注入模式為 AUTOWIRE_BY_NAME 或者 AUTOWIRE_BY_TYPE,則通過下面的方式獲取屬性值
    2. pvs 封裝成 MutablePropertyValues 物件 newPvs(允許對屬性進行相關操作)
    3. AUTOWIRE_BY_NAME 模式,通過名稱獲取相關屬性值,保存在 newPvs 中,呼叫 autowireByName(...) 方法
    4. AUTOWIRE_BY_TYPE 模式,通過型別獲取相關屬性值,保存在 newPvs 中,呼叫 autowireByType(...) 方法
    5. newPvs 復制給 pvs
  5. 通過 InstantiationAwareBeanPostProcessor 處理器(如果有)對 pvs 進行處理

    1. 遍歷所有的 BeanPostProcessor
    2. 如果為 InstantiationAwareBeanPostProcessor 型別,則呼叫其 postProcessProperties(...) 方法,對 pvs 進行后置處理
    3. 如果上一步的處理結果為空,可能是新版本導致的(Spring 5.1 之前沒有上面這個方法),則需要兼容老版本
      1. 嘗試找到這個 Bean 的所有 java.beans.PropertyDescriptor 屬性描述器(包含這個屬性的所有資訊)
      2. 呼叫處理器的 postProcessPropertyValues(...) 方法,對 pvs 進行后置處理
      3. 如果處理后的 PropertyValues 物件為空,直接 return,則不會呼叫后面的處理器,也不會進行接下來的屬性填充
    4. 將處理后的 pvsToUse 復制給 pvs
  6. 依賴檢查

    1. 找到這個 Bean 的所有 java.beans.PropertyDescriptor 屬性描述器(包含這個屬性的所有資訊)
    2. 進行依賴檢查,如果沒有找到對應的屬性值,則根據檢查策略進行拋出例外(默認不會)
  7. 如果 pvs 不為空,則將里面的屬性值設定到當前 Bean 對應的屬性中(依賴注入),呼叫 applyPropertyValues(...) 方法

    前面找到的屬性值并沒有設定到 Bean 中,且屬性值可能是一個運算式,型別也可能也不對,需要先進行處理和型別轉換,然后再設定到該實體物件中


整個的屬性填充程序非常的復雜,接下來進行概括:

  • 允許你對實體化物件進行后置處理,處理結果為 false 表示不需要進行接下來的屬性填充程序
  • 根據注入模式,找到沒有配置屬性值的物件屬性,然后找到對應的 Bean,默認注入模式為不注入
  • 允許你對屬性值進行后置處理,例如 @Autowired@Value 等注解標注的屬性會通過這里找到對應的屬性值(或物件)
  • 上述程序僅找到了屬性值,還沒設定到當前實體物件中,所以最后一步才是真正的屬性填充

因為整個程序比較繁瑣,涉及到的方法行數比較多,所以另起一篇《Bean 的屬性填充階段》文章進行分析

8. 初始化 Bean

對應代碼段:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Initialize the bean instance.
// 開始初始化 `bean`
Object exposedObject = bean;
try {
    // <4> 對 `bean` 進行屬性填充,注入對應的屬性值
    populateBean(beanName, mbd, instanceWrapper);
    // <5> 初始化這個 `exposedObject`,呼叫其初始化方法
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
    if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
    }
    else {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
    }
}

實體物件已經有了,且相關屬性已經填充了,那么接下來需要進行相關初始化作業,也就是上面的第 <5>

initializeBean

// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) { // 安全模式
        // <1> Aware 介面的回呼
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> { 
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        // <1> Aware 介面的回呼
        invokeAwareMethods(beanName, bean);
    }

    /**
     * <2> **初始化**階段的**前置處理**,執行所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法
     *
     * 在 {@link AbstractApplicationContext#prepareBeanFactory} 方法中會添加 {@link ApplicationContextAwareProcessor} 處理器
     * 用于處理其他 Aware 介面的回呼,例如ApplicationContextAware、EnvironmentAware、ApplicationEventPublisherAware
     *
     * 在 {@link AnnotationConfigUtils#registerAnnotationConfigProcessors} 方法中會注冊 {@link CommonAnnotationBeanPostProcessor} 處理器
     * 在這里會執行 @PostConstruct 注解標注的方法
     */
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // <3> 激活自定義的初始化方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    /**
     * <4> **初始化**階段的**后置處理**,執行所有 BeanPostProcessor 的 postProcessAfterInitialization 方法
     *
     * 在 {@link AbstractApplicationContext#prepareBeanFactory} 方法中會添加 {@link ApplicationListenerDetector} 處理器
     * 如果是單例 Bean 且為 ApplicationListener 型別,則添加到 Spring 應用背景關系,和 Spring 事件相關
     */
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

初始化程序如下:

  1. Aware 介面的回呼,呼叫 invokeAwareMethods(final String beanName, final Object bean) 方法,如下:

    // AbstractAutowireCapableBeanFactory.java
    private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }
    

    如果是 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware,則呼叫其 setXxx 方法

  2. 初始化階段的前置處理,執行所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,如下:

    // AbstractAutowireCapableBeanFactory.java
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {
    
        Object result = existingBean;
        // 遍歷所有 BeanPostProcessor
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 初始化的前置處理,回傳 `current` 處理結果
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            // 處理結果為空,則直接回傳 `result`
            if (current == null) {
                return result;
            }
            // 否則,`result` 復制 `current`
            result = current;
        }
        return result;
    }
    

    例如 Spring 內部有下面兩個處理器

    ApplicationContextAwareProcessor:ApplicationContextAware、ApplicationEventPublisherAware、EnvironmentAware 等其他 Aware 介面的回呼

    CommonAnnotationBeanPostProcessor@PostConstruct 注解標注的方法的呼叫

  3. 激活自定義的初始化方法,如下:

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {
        // <1> InitializingBean 介面的回呼(如果是)
        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) { // 安全模式
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        // 呼叫其 afterPropertiesSet() 方法
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                } catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            } else {
                // 呼叫其 afterPropertiesSet() 方法
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) 
                && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) 
                && !mbd.isExternallyManagedInitMethod(initMethodName)) {
                // <2> 呼叫通過 `init-method` 指定的初始化方法(反射機制)
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
    
    1. InitializingBean 介面的回呼(如果是),呼叫其 afterPropertiesSet() 方法
    2. 呼叫通過 init-method 指定的初始化方法(反射機制)
  4. 初始化階段的后置處理,執行所有 BeanPostProcessor 的 postProcessAfterInitialization 方法,如下:

    // AbstractAutowireCapableBeanFactory.java
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {
        Object result = existingBean;
        // 遍歷所有 BeanPostProcessor
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 初始化的后置處理,回傳 `current` 處理結果
            Object current = processor.postProcessAfterInitialization(result, beanName);
            // 處理結果為空,則直接回傳 `result`
            if (current == null) {
                return result;
            }
            // 否則,`result` 復制 `current`
            result = current;
        }
        return result;
    }
    

    例如 Spring 內部有一個 ApplicationListenerDetector 處理器,如果是單例 Bean 且為 ApplicationListener 型別,則添加到 Spring 應用背景關系,和 Spring 事件相關


整個的初始化程序并不復雜,其中也有對應的擴展點,初始化前置處理和后置處理,總的概括如下:

  1. Aware 介面的回呼

  2. JSR-250 @PostConstruct 標注的方法的呼叫

  3. InitializingBean#afterPropertiesSet 方法的回呼

  4. init-method 初始化方法的呼叫

9. 回圈依賴注入的檢查

對應代碼段:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// <6> 回圈依賴注入的檢查
if (earlySingletonExposure) {
    // <6.1> 獲取當前正在創建的 `beanName` 被依賴注入的早期參考
    // 注意,這里有一個入參是 `false`,不會呼叫上面第 `3` 步的 ObjectFactory 實作類
    // 也就是說當前 `bean` 如果出現回圈依賴注入,這里才能獲取到提前暴露的參考
    Object earlySingletonReference = getSingleton(beanName, false);
    // <6.2> 如果出現了回圈依賴注入,則進行接下來的檢查作業
    if (earlySingletonReference != null) {
        // <6.2.1> 如果 `exposedObject` 沒有在初始化階段中被改變,也就是沒有被增強
        // 則使用提前暴露的那個參考
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        }
        // <6.2.2> 否則,`exposedObject` 已經不是被別的 Bean 依賴注入的那個 Bean
        else if (!this.allowRawInjectionDespiteWrapping // 是否允許注入未加工的 Bean,默認為 false,這里取非就為 true
                && hasDependentBean(beanName)) { // 存在依賴 `beanName` 的 Bean(通過 `depends-on` 配置)
            // 獲取依賴當前 `beanName` 的 Bean 們的名稱(通過 `depends-on` 配置)
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            // 接下來進行判斷,如果依賴 `beanName` 的 Bean 已經創建
            // 說明當前 `beanName` 被注入了,而這里最終的 `bean` 被包裝過,不是之前被注入的
            // 則拋出例外
            for (String dependentBean : dependentBeans) {
                if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                    actualDependentBeans.add(dependentBean);
                }
            }
            if (!actualDependentBeans.isEmpty()) {
                throw new BeanCurrentlyInCreationException(beanName,
                        "Bean with name '" + beanName + "' has been injected into other beans [" +
                        StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                        "] in its raw version as part of a circular reference, but has eventually been " +
                        "wrapped. This means that said other beans do not use the final version of the " +
                        "bean. This is often the result of over-eager type matching - consider using " +
                        "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
        }
    }
}

在前面 6. 提前暴露當前 Bean 小節中,如果提前暴露了 Bean,則可能存在回圈依賴注入,這里需要進行一些檢查,過程大致如下:

  1. 獲取當前正在創建的 beanName 被依賴注入的早期參考,這里呼叫方法也就是從快取中獲取單例 Bean 的方法,

    注意,這里有一個入參是 false,不會呼叫前面 6. 提前暴露當前 Bean 小節中快取的 ObjectFactory 實作類,也就是說當前 bean 如果出現回圈依賴注入,這里才能獲取到提前暴露的參考

  2. 如果上一步獲取到了提前暴露的參考,也就是出現了回圈依賴注入,則進行接下來的檢查作業

    1. 如果 exposedObject 沒有在初始化階段中被改變,也就是沒有被增強,則使用提前暴露的那個參考
    2. 否則,exposedObject 已經不是被別的 Bean 依賴注入的那個 Bean,則進行相關判斷

當出現回圈依賴注入,這里會檢查填充屬性和初始化的程序中是否改變了這個 beanName,改變了的話需要判斷依賴當前 beanName 的 Bean 們是否已經創建了,如果已經創建了,那么可能它拿到的 beanName 不是這里初始化后的物件(被修改了),所以需要拋出例外

10. 注冊可銷毀的 Bean

對應代碼段:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法
// Register bean as disposable.
try {
    /**
     * <7> 為當前 `bean` 注冊 DisposableBeanAdapter(如果需要的話),用于 Bean 生命周期中的銷毀階段
     * 可以看到 {@link DefaultSingletonBeanRegistry#destroySingletons()} 方法
     */
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
    throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

這里會呼叫 registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) 方法,如下:

// AbstractBeanFactory.java
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
    if (!mbd.isPrototype() // 不是原型模式
            && requiresDestruction(bean, mbd)) // 有銷毀的必要,也就是定義了銷毀方法
    {
        if (mbd.isSingleton()) { // 單例模式
            // Register a DisposableBean implementation that performs all destruction work for the given bean: 
            // DestructionAwareBeanPostProcessors, DisposableBean interface, custom destroy method.
            // 創建一個 DisposableBeanAdapter 物件封裝這個 Bean,然后保存在 `disposableBeans` Map 集合中
            registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
        else { // 其他模式
            // A bean with a custom scope...
            Scope scope = this.scopes.get(mbd.getScope());
            if (scope == null) {
                throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
            }
            // 創建一個 DisposableBeanAdapter 物件封裝這個 Bean,往其他模式的 Scope 物件里面注冊
            scope.registerDestructionCallback(beanName,
                    new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
        }
    }
}

如果不是原型模式,并且有銷毀的必要,也就是定義了銷毀方法,則需要創建一個 DisposableBeanAdapter 物件封裝這個 Bean,在生命周期的銷毀階段需要先通過這個物件先執行銷毀方法,這個物件如何存盤的:

  • 單例模式:保存在 disposableBeans Map 集合中
  • 其他模式:往 Scope 物件里面注冊

11. 回傳 Bean

經過上面一系列的程序,實體化、屬性填充、初始化等階段,已經創建好了這個 Bean,最后直接回傳

總結

當我們顯示或者隱式地呼叫AbstractBeanFactorygetBean(...) 方法時,會觸發 Bean 的加載,加載程序在上一篇《開啟 Bean 的加載》文章中已經分析過,對于不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactorycreateBean(...) 方法進行創建,創建 Bean 的程序如下:

  • Class 物件加載階段
  • 實體化前階段(如果回傳了一個物件則直接回傳,不會進行下面的階段)
  • 實體化階段
  • 實體化后階段
  • 提前暴露單例 Bean(回圈依賴處理的關鍵)
  • 屬性填充階段
  • Aware 介面回呼階段
  • 初始化前階段
  • 初始化階段
  • 初始化后階段

創建 Bean 的程序非常復雜,在不同的階段都會講到 BeanPostProcessor(及其子類)的身影,Spring 內部很多功能都是基于該處理器介面實作的,當然開發者也可以通過其進行拓展,使得框架變得非常靈活,其中 Bean 的實體化屬性填充兩個階段比較復雜,這里沒有深入分析,可參考后續文章,提前暴露單例 Bean 回圈依賴處理的關鍵,后續文章也會再次分析

你是否還有疑問,例如我們常用的 @Autowired、@Value、@Resource、@Bean、@Import、@ComponentScan 等注解會在哪被決議呢?

別著急,后面的文章都會講到,我們先把 Bean 的加載程序搞明白,然后再講 Spring 應用背景關系的生命周期

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/265026.html

標籤:Java

上一篇:銀行科技到底怎么樣?我曾經的四年告訴你 !

下一篇:一文入門Java Stream流,太強了

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more