死磕Spring之IoC篇 - Bean 的例項化階段

月圓吖發表於2021-03-02

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

Spring 版本:5.1.14.RELEASE

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

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

Bean 的例項化階段

當我們顯示或者隱式地呼叫AbstractBeanFactorygetBean(...) 方法時,會觸發 Bean 的載入,在《開啟 Bean 的載入》文章中分析了整個載入過程。

對於不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactorycreateBean(...) 方法進行建立,在上一篇《Bean 的建立過程》文章中分析了整個建立過程。在建立 Bean 的過程中,需要先獲取其 Class 物件,然後通過構造方法建立一個例項物件(反射機制),再進行後續的屬性填充和初始化工作。整個的例項化過程非常複雜,因為需要找到最匹配的構造方法,還需要找到該方法的入參,所以會有各種處理,本文將會分析建立 Bean 過程中的例項化階段。

回顧

先來回顧一下建立 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)

如果是單例模式,則先嚐試從 factoryBeanInstanceCache 快取(儲存 FactoryBean 型別的物件)中獲取例項物件,並從快取中移除。目前在建立 Bean 的過程中沒發現往這個集合中新增快取,暫時忽略。我們直接看到下面的一步,呼叫 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) {
        // <7.1> 如果存在優先的構造方法,則從裡面找到最匹配的一個,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制)
        return autowireConstructor(beanName, mbd, ctors, null);
    }

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

過程大致如下:

  1. 獲取 beanName 對應的 Class 物件

  2. 如果存在 Supplier 例項化回撥介面,則使用給定的回撥方法建立一個例項物件,呼叫 obtainFromSupplier(...) 方法建立

  3. 如果配置了 factory-method 工廠方法,則呼叫該方法來建立一個例項物件,通過 @Bean 標註的方法會通過這裡進行建立,呼叫 instantiateUsingFactoryMethod(...) 方法建立


如果上面兩種情況都不是,那麼就進行接下來正常建立 Bean 例項的一個過程

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

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

    1. 如果這個構造方法有入參,則找到最匹配的構造方法,這裡會拿到已經被解析出來的這個方法,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制),呼叫 autowireConstructor(...) 方法建立
    2. 否則,沒有入參,直接呼叫解析出來構造方法,返回一個例項物件(反射機制),呼叫 instantiateBean(...) 方法建立
  3. 如果最匹配的構造方法還沒開始解析,那麼需要找到一個最匹配的構造方法,然後建立一個例項物件

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

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

      則找到最匹配的構造方法,如果 ctors 不為空,會從這裡面找一個最匹配的,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制),呼叫 autowireConstructor(...) 方法建立

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

    1. 如果存在優先的構造方法,則從裡面找到最匹配的一個,並找到入參(構造器注入),然後呼叫該方法返回一個例項物件(反射機制),呼叫 autowireConstructor(...) 方法建立
  5. 如果上面多種情況都不滿足,那隻能使用兜底方法了,直接呼叫預設構造方法返回一個例項物件(反射機制),呼叫 instantiateBean(...) 方法建立


整個的例項化過程非常的複雜,主要分為以下幾種情況:

  1. 指定了 Supplier 例項化回撥介面,則回撥該介面,返回一個例項物件
  2. 配置了 factory-method 工廠方法建立當前 Bean,則找到這個方法,然後建立一個例項物件(@Bean 註解底層原理也是這種方式)
  3. 找到一個最匹配的構造方法,返回一個例項物件,這個構造方法會設定到這個 RootBeanDefinition 中,避免再次解析,提高效能
  4. 兜底方法,使用預設構造方法返回一個例項物件

這四種情況,其實就分別對應上面四個加粗的方法,接下來依次分析這四個方法

obtainFromSupplier 方法

obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) 方法,通過 Supplier 回撥介面獲取一個例項物件,方法如下:

// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
    Object instance;

    // 獲得原當前執行緒正在建立的 Bean 的名稱
    String outerBean = this.currentlyCreatedBean.get();
    // 設定當前執行緒正在建立的 Bean 的名稱
    this.currentlyCreatedBean.set(beanName);
    try {
        // <1> 呼叫 Supplier 的 get(),返回一個例項物件
        instance = instanceSupplier.get();
    }
    finally {
        if (outerBean != null) {
            // 設定原當前執行緒正在建立的 Bean 的名稱到當前執行緒變數中
            this.currentlyCreatedBean.set(outerBean);
        }
        else {
            this.currentlyCreatedBean.remove();
        }
    }

    // 未建立 Bean 物件,則建立 NullBean 空物件
    if (instance == null) {
        instance = new NullBean();
    }
    // <2> 將例項物件封裝成 BeanWrapper 物件
    BeanWrapper bw = new BeanWrapperImpl(instance);
    // <3> 初始化這個 BeanWrapper 物件
    initBeanWrapper(bw);
    return bw;
}

過程如下:

  1. 呼叫 Supplier 介面的 get(),返回 instance 例項物件
  2. instance 封裝成 BeanWrapper 物件 bw
  3. bw 進行初始化,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器

整個過程比較簡單

instantiateUsingFactoryMethod 方法

通過 factoryMethodName 工廠方法建立一個例項物件,例如 XML 配置的 factory-method 屬性或者 @Bean 標註的方法都會解析成 factoryMethodName 屬性

這個過程非常複雜,你可以理解為去找到最匹配的 Method 工廠方法,獲取相關入參(依賴注入),然後呼叫該方法返回一個例項物件(反射機制),方法如下:

// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper instantiateUsingFactoryMethod(
        String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
    return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

建立 ConstructorResolver 物件,然後呼叫其 instantiateUsingFactoryMethod(...) 方法,如下:

// ConstructorResolver.java
public BeanWrapper instantiateUsingFactoryMethod(
        String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

    // 構造 BeanWrapperImpl 物件
    BeanWrapperImpl bw = new BeanWrapperImpl();
    // 初始化 BeanWrapperImpl,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器
    this.beanFactory.initBeanWrapper(bw);

    // -------------------------獲取工廠方法的相關資訊-------------------------
    // <1> 獲取工廠方法的相關資訊

    // 工廠方法所在類對應的 Bean(靜態方法不會有)
    Object factoryBean;
    // 工廠方法所在類的 Class 物件
    Class<?> factoryClass;
    // 是否為 static 修飾的靜態方法
    boolean isStatic;

    // 獲取工廠方法所在類對應的 Bean 的名稱(靜態方法不會有)
    String factoryBeanName = mbd.getFactoryBeanName();
    // <1.1> 非靜態方法
    if (factoryBeanName != null) {
        if (factoryBeanName.equals(beanName)) {
            throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                    "factory-bean reference points back to the same bean definition");
        }
        // 獲取工廠方法所在類對應的 Bean,不然無法呼叫工廠方法
        factoryBean = this.beanFactory.getBean(factoryBeanName);
        // 如果是單例模式,已經存在對應的 Bean,則丟擲重複建立的異常
        if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
            throw new ImplicitlyAppearedSingletonException();
        }
        factoryClass = factoryBean.getClass();
        isStatic = false;
    }
    // <1.2> 靜態方法
    else {
        // It's a static factory method on the bean class.
        // 靜態方法沒有找到對應的 Class 物件無法被呼叫,則丟擲異常
        if (!mbd.hasBeanClass()) {
            throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                    "bean definition declares neither a bean class nor a factory-bean reference");
        }
        factoryBean = null;
        factoryClass = mbd.getBeanClass();
        isStatic = true;
    }

    // -------------------------嘗試獲取工廠方法物件和入參-------------------------
    // <2> 嘗試獲取工廠方法物件和引數

    // 工廠方法物件
    Method factoryMethodToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    // 方法引數
    Object[] argsToUse = null;

    // <2.1> 如果方法入參指定了引數,則直接使用
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    // <2.2> 否則,嘗試從 RootBeanDefinition 中獲取已解析出來的工廠方法和入參
    else {
        Object[] argsToResolve = null;
        // 因為可能前面解析了,會臨時快取,避免再次解析
        synchronized (mbd.constructorArgumentLock) { // 加鎖
            factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
            // 如果工廠方法被解析了,那麼引數也可能解析過
            if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
                // Found a cached factory method...
                argsToUse = mbd.resolvedConstructorArguments;
                if (argsToUse == null) {
                    // 沒有解析過的引數,則嘗試從 RootBeanDefinition 中獲取未被解析過的引數
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        // 如果獲取到了未被解析過的入參,則進行解析
        if (argsToResolve != null) {
            // 處理引數值,型別轉換,例如給定方法 A(int, int),配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
        }
    }

    // -------------------------找到所有匹配的工廠方法-------------------------
    // <3> 如果上一步沒有找到工廠方法物件或方法入參集合,則需要進行接下來的解析過程,首先找到所有匹配的工廠方法

    if (factoryMethodToUse == null || argsToUse == null) {
        // Need to determine the factory method...
        // Try all methods with this name to see if they match the given arguments.
        // <3.1> 獲取工廠方法所在的類的例項 Class 物件,因為可能是 Cglib 提升過的子類
        factoryClass = ClassUtils.getUserClass(factoryClass);

        // <3.2> 獲取工廠方法所在的類中所有方法物件
        Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
        // <3.3> 找到這個類中匹配的工廠方法
        List<Method> candidateList = new ArrayList<>();
        for (Method candidate : rawCandidates) {
            if (Modifier.isStatic(candidate.getModifiers()) == isStatic // 是否和 `isStatic` 匹配
                    && mbd.isFactoryMethod(candidate)) { // 和定義的工廠方法的名稱是否相等
                candidateList.add(candidate);
            }
        }

        // <3.4> 如果只有一個匹配的方法,且這個方法沒有給指定的入參,且本身也沒有定義引數,且這個方法沒有定義入參
        // 則直接呼叫這個方法建立一個例項物件(反射機制),並返回
        if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
            Method uniqueCandidate = candidateList.get(0);
            if (uniqueCandidate.getParameterCount() == 0) {
                mbd.factoryMethodToIntrospect = uniqueCandidate;
                synchronized (mbd.constructorArgumentLock) {
                    mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                    mbd.constructorArgumentsResolved = true;
                    mbd.resolvedConstructorArguments = EMPTY_ARGS;
                }
                bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
                return bw;
            }
        }

        // -------------------------開始找最匹配的工廠方法-------------------------
        // <4> 開始找最匹配的工廠方法

        // 將匹配的工廠方法轉換成陣列
        Method[] candidates = candidateList.toArray(new Method[0]);
        // 將匹配的方法進行排序,public 方法優先,入參個數多的優先
        AutowireUtils.sortFactoryMethods(candidates);

        // 用於承載解析後的方法引數值
        ConstructorArgumentValues resolvedValues = null;
        // 是否是構造器注入
        boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
        int minTypeDiffWeight = Integer.MAX_VALUE;
        // 匹配方法的集合
        Set<Method> ambiguousFactoryMethods = null;

        // -------------------------確定方法引數的入引數量-------------------------
        // <5> 確定方法引數的入引數量,匹配的方法的入引數量要多餘它
        // 方法的引數數量的最小值
        int minNrOfArgs;
        // <5.1> 如果當前方法指定了入參,則使用其個數作為最小值
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        // <5.1> 否則,從 RootBeanDefinition 解析出方法的引數個數作為最小值
        else {
            // We don't have arguments passed in programmatically, so we need to resolve the
            // arguments specified in the constructor arguments held in the bean definition.
            // RootBeanDefinition 定義了引數值
            if (mbd.hasConstructorArgumentValues()) {
                // 方法的引數
                ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                resolvedValues = new ConstructorArgumentValues();
                // 解析定義的引數值,放入 `resolvedValues` 中,並返回引數個數
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }
            else {
                minNrOfArgs = 0;
            }
        }

        // 記錄 UnsatisfiedDependencyException 異常的集合
        LinkedList<UnsatisfiedDependencyException> causes = null;

        // 遍歷匹配的方法
        for (Method candidate : candidates) {
            // 方法體的引數
            Class<?>[] paramTypes = candidate.getParameterTypes();

            if (paramTypes.length >= minNrOfArgs) {
                // -------------------------解析出工廠方法的入參-------------------------
                // <6> 解析出工廠方法的入參

                // 儲存引數的物件
                ArgumentsHolder argsHolder;

                // <6.1> 如果當前方法指定了入參,則直接使用
                if (explicitArgs != null) {
                    // Explicit arguments given -> arguments length must match exactly.
                    // 顯示給定引數,引數長度必須完全匹配
                    if (paramTypes.length != explicitArgs.length) {
                        continue;
                    }
                    // 根據引數建立引數持有者 ArgumentsHolder 物件
                    argsHolder = new ArgumentsHolder(explicitArgs);
                }
                // <6.2> 否則,通過**依賴注入**獲取入參
                else {
                    // Resolved constructor arguments: type conversion and/or autowiring necessary.
                    // 為提供引數,解析構造引數
                    try {
                        String[] paramNames = null;
                        // 獲取 ParameterNameDiscoverer 引數名稱探測器
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        // 獲取方法的引數名稱
                        if (pnd != null) {
                            paramNames = pnd.getParameterNames(candidate);
                        }
                        // 解析出方法的入參,引數值會被依賴注入
                        argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
                    }
                    catch (UnsatisfiedDependencyException ex) {
                        // 若發生 UnsatisfiedDependencyException 異常,新增到 causes 中。
                        if (logger.isTraceEnabled()) {
                            logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
                        }
                        // Swallow and try next overloaded factory method.
                        if (causes == null) {
                            causes = new LinkedList<>();
                        }
                        causes.add(ex);
                        continue;
                    }
                }

                // -------------------------根據權重獲取最匹配的方法-------------------------
                // <7> 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個

                // 判斷解析建構函式的時候是否以寬鬆模式還是嚴格模式,預設為 true
                // 嚴格模式:解析建構函式時,必須所有的都需要匹配,否則丟擲異常
                // 寬鬆模式:使用具有"最接近的模式"進行匹配
                // typeDiffWeight:型別差異權重
                int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                        argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                // Choose this factory method if it represents the closest match.
                // 代表最匹配的結果,則選擇作為符合條件的方法
                if (typeDiffWeight < minTypeDiffWeight) {
                    factoryMethodToUse = candidate;
                    argsHolderToUse = argsHolder;
                    argsToUse = argsHolder.arguments;
                    minTypeDiffWeight = typeDiffWeight;
                    ambiguousFactoryMethods = null;
                }
                // Find out about ambiguity: In case of the same type difference weight
                // for methods with the same number of parameters, collect such candidates
                // and eventually raise an ambiguity exception.
                // However, only perform that check in non-lenient constructor resolution mode,
                // and explicitly ignore overridden methods (with the same parameter signature).
                // 如果具有相同引數數量的方法具有相同的型別差異權重,則收集此型別選項
                // 但是,僅在非寬鬆建構函式解析模式下執行該檢查,並顯式忽略重寫方法(具有相同的引數簽名)
                else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
                        !mbd.isLenientConstructorResolution() &&
                        paramTypes.length == factoryMethodToUse.getParameterCount() &&
                        !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
                    // 查詢到多個可匹配的方法
                    if (ambiguousFactoryMethods == null) {
                        ambiguousFactoryMethods = new LinkedHashSet<>();
                        ambiguousFactoryMethods.add(factoryMethodToUse);
                    }
                    ambiguousFactoryMethods.add(candidate);
                }
            }
        }

        // <8> 沒有找到對應的工廠方法,則丟擲異常
        if (factoryMethodToUse == null) {
            if (causes != null) {
                UnsatisfiedDependencyException ex = causes.removeLast();
                for (Exception cause : causes) {
                    this.beanFactory.onSuppressedException(cause);
                }
                throw ex;
            }
            List<String> argTypes = new ArrayList<>(minNrOfArgs);
            if (explicitArgs != null) {
                for (Object arg : explicitArgs) {
                    argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
                }
            }
            else if (resolvedValues != null) {
                Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
                valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
                valueHolders.addAll(resolvedValues.getGenericArgumentValues());
                for (ValueHolder value : valueHolders) {
                    String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
                            (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
                    argTypes.add(argType);
                }
            }
            String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "No matching factory method found: " +
                    (mbd.getFactoryBeanName() != null ?
                        "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
                    "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
                    "Check that a method with the specified name " +
                    (minNrOfArgs > 0 ? "and arguments " : "") +
                    "exists and that it is " +
                    (isStatic ? "static" : "non-static") + ".");
        }
        else if (void.class == factoryMethodToUse.getReturnType()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Invalid factory method '" + mbd.getFactoryMethodName() +
                    "': needs to have a non-void return type!");
        }
        else if (ambiguousFactoryMethods != null) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Ambiguous factory method matches found in bean '" + beanName + "' " +
                    "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
                    ambiguousFactoryMethods);
        }

        // <9> 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析
        if (explicitArgs == null && argsHolderToUse != null) {
            mbd.factoryMethodToIntrospect = factoryMethodToUse;
            argsHolderToUse.storeCache(mbd, factoryMethodToUse);
        }
    }

    Assert.state(argsToUse != null, "Unresolved factory method arguments");
     // <10> 呼叫工廠方法建立一個例項物件(反射機制),並設定到 `bw` 中
    bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
    return bw;
}

這個方法我真的是吐了?,也太長了吧,硬著頭皮看完了一部分,參考檔案:ConstructorResolver.java

對於過程不感興趣的可以跳過直接看下面的概括,過程大致如下:

先建立一個 BeanWrapperImpl 物件 bw,並初始化,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器


  1. 獲取工廠方法的相關資訊,根據 RootBeanDefinition 的 factoryBeanName 屬性判斷是否靜態方法,這個屬性表示這個工廠方法所在類對應 Bean 的名稱,當然靜態方法“不屬於”這個 Bean,所以它的這個屬性為空
    1. factoryBeanName 屬性不為空,表示不是靜態方法,則需要根據 factoryBeanName 找到(依賴查詢)對應的 Bean,作為 factoryBean
    2. 否則,就是靜態方法,獲取所在類的 Class 物件即可

這一步找到了三個物件:factoryBean(工廠方法所在類對應的 Bean,靜態方法不會有)、factoryClass(工廠方法所在類的 Class 物件)、isStatic(是否為靜態方法)。所以想要通過工廠方法獲取一個 Bean,則需要方法所在類對應的 Bean 先初始化,然後才能呼叫這個方法建立 Bean;而靜態方法就不用,因為它可以根據所在類的 Class 物件就能呼叫這個方法建立 Bean,這就是兩者的區別。


  1. 嘗試獲取工廠方法 Method 物件和入參

    1. 如果方法入參指定了引數,則直接使用

    2. 否則,嘗試從 RootBeanDefinition 中獲取已解析出來的工廠方法和入參,如果獲取到了未被解析過的入參,則進行解析(型別轉換)

      例如給定方法 A(int, int),配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)

這一步嘗試獲取兩個物件:factoryMethodToUse(對應的工廠方法 Method)、argsToUse(工廠方法的入參集合)


  1. 如果上一步沒有找到工廠方法物件或方法入參集合,找到所有匹配的工廠方法,首先找到所有匹配的工廠方法
    1. 獲取工廠方法所在的類的例項 Class 物件,因為可能是 Cglib 提升過的子類
    2. 獲取工廠方法所在的類中所有方法物件
    3. 找到這個類中匹配的工廠方法,是否和 isStatic 匹配,並且和定義的工廠方法的名稱是否相等
    4. 如果只有一個匹配的方法,且這個方法沒有給指定的入參,且本身也沒有定義引數,且這個方法沒有定義入參,則直接呼叫這個方法建立一個例項物件(反射機制),並返回

上面第 3.3 步找到的通常只有一個,如果沒有入參則可以直接進入第 3.4 步,使用這個方法建立一個例項物件。不過你可能定義了過載方法,也可能定義了方法引數,所以需要進行接下來的解析過程


  1. 開始找最匹配的工廠方法,先排序,public 方法優先,入參個數多的優先
  2. 確定方法引數的入引數量,匹配的方法的入引數量要多餘它
    1. 如果當前方法指定了入參,則使用其個數作為最小值
    2. 否則,從 RootBeanDefinition 解析出方法的引數個數作為最小值,沒有定義則設定為 0

這一步主要是確定入參的個數,並排序所有匹配的方法,接下來會遍歷所有匹配的方法


  1. 解析出工廠方法的入參
    1. 如果當前方法指定了入參,則直接使用
    2. 否則,通過依賴注入獲取入參

這一步會找到這個方法的入參,依賴注入的方式


  1. 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個

通常情況下,我們只有一個匹配的方法,如果存在多個,會根據方法的引數型別進行權重


  1. 沒有找到對應的工廠方法,則丟擲異常
  2. 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析

會快取這幾個資料:resolvedConstructorOrFactoryMethod(已經解析出來的工廠方法)、constructorArgumentsResolved(方法入參已經解析出來了 true)、resolvedConstructorArguments(解析出來的入參)


  1. 呼叫工廠方法建立一個例項物件(反射機制),並設定到 bw

上面整個過程非常複雜,這裡進行簡單概括

  • 找到對應的工廠方法,如果是非靜態方法,則需要先依賴查詢到所在類對應的 Bean,因為需要根據這個 Bean 去呼叫對應的工廠方法,而靜態方法不用,可以根據其 Class 物件呼叫對應的工廠方法

  • 如果工廠方法有入參,則需要注入相關物件(依賴注入

  • 呼叫這個方法(反射機制),返回一個例項物件

autowireConstructor 方法

這個過程和上一個方法一樣非常複雜,不過差不太多,你可以理解為去找到當前 Bean 的構造方法,獲取相關入參(構造器注入),然後呼叫該構造方法返回一個例項物件(反射機制),方法如下:

// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper autowireConstructor(
        String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
    return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

建立 ConstructorResolver 物件,然後呼叫其 autowireConstructor(...) 方法,如下:

// ConstructorResolver.java
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
        @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

    // 構造 BeanWrapperImpl 物件
    BeanWrapperImpl bw = new BeanWrapperImpl();
    // 初始化 BeanWrapperImpl,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器
    this.beanFactory.initBeanWrapper(bw);

    // -------------------------嘗試獲取構造方法和入參-------------------------
    // <1> 嘗試獲取構造方法和入參

    // 構造方法
    Constructor<?> constructorToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    // 構造方法的入參集合
    Object[] argsToUse = null;

    // <1.1> 如果當前方法入參指定了引數,則直接使用
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    // <1.2> 否則,嘗試從 RootBeanDefinition 中獲取已解析出來的構造方法和入參
    else {
        // 因為可能前面解析了,會臨時快取,避免再次解析
        Object[] argsToResolve = null;
        synchronized (mbd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
            // 如果構造方法被解析了,那麼引數也可能解析過
            if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                // Found a cached constructor...
                argsToUse = mbd.resolvedConstructorArguments;
                if (argsToUse == null) {
                    // 沒有解析過的引數,則嘗試從 RootBeanDefinition(合併後)中獲取未被解析過的引數
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        // 如果獲取到了未被解析過的入參
        if (argsToResolve != null) {
            // 處理引數值,型別轉換,例如給定方法 A(int, int),配配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
        }
    }

    // -------------------------開始獲取構造方法和入參-------------------------
    // <2> 如果上一步沒有找到構造方法或入參集合,找到所有匹配的工廠方法,首先找到所有匹配的構造方法

    if (constructorToUse == null || argsToUse == null) {
        // Take specified constructors, if any.
        // <2.1> 獲取所有的構造方法,如果當前方法指定了構造方法的集合,則使用這個集合
        Constructor<?>[] candidates = chosenCtors;
        if (candidates == null) {
            Class<?> beanClass = mbd.getBeanClass();
            try {
                candidates = (mbd.isNonPublicAccessAllowed() ?
                        beanClass.getDeclaredConstructors() : beanClass.getConstructors());
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                        "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
            }
        }

        // <2.2> 如果構造方法只有一個,且當前方法的入參沒有指定引數,且本身也沒有定義引數,且這個構造方法沒有定義入參
        // 則直接呼叫這個構造方法建立一個例項物件(反射機制),並返回
        if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
            Constructor<?> uniqueCandidate = candidates[0];
            if (uniqueCandidate.getParameterCount() == 0) {
                synchronized (mbd.constructorArgumentLock) {
                    mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                    mbd.constructorArgumentsResolved = true;
                    mbd.resolvedConstructorArguments = EMPTY_ARGS;
                }
                bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
                return bw;
            }
        }

        // Need to resolve the constructor.
        // 是否是構造器注入
        boolean autowiring = (chosenCtors != null ||
                mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
        // 用於承載解析後的方法引數值
        ConstructorArgumentValues resolvedValues = null;

        // -------------------------確定構造方法的入引數量-------------------------
        // <3> 確定構造引數的入引數量,匹配的方法的入引數量要多餘它
        // 方法的引數數量的最小值
        int minNrOfArgs;
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        // 從 RootBeanDefinition 解析出方法的引數個數作為最小值
        else {
            ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
            resolvedValues = new ConstructorArgumentValues();
            minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
        }

        // <4> 將所有的構造方法進行排序,public 方法優先,入參個數多的優先
        AutowireUtils.sortConstructors(candidates);
        int minTypeDiffWeight = Integer.MAX_VALUE;
        Set<Constructor<?>> ambiguousConstructors = null;
        LinkedList<UnsatisfiedDependencyException> causes = null;

        // 遍歷所有建構函式
        for (Constructor<?> candidate : candidates) {
            // 獲取該構造方法的引數型別
            Class<?>[] paramTypes = candidate.getParameterTypes();

            // 如果前面已經找到匹配的構造方法和入參,則直接結束迴圈
            if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
                // Already found greedy constructor that can be satisfied ->
                // do not look any further, there are only less greedy constructors left.
                break;
            }
            // 如果這個構造方法的引數個數小於入引數量,則跳過
            if (paramTypes.length < minNrOfArgs) {
                continue;
            }

            // -------------------------解析出構造方法的入參-------------------------
            // <5> 解析出構造方法的入參

            // 儲存引數的物件
            ArgumentsHolder argsHolder;
            // <5.2> 通過**依賴注入**獲取入參
            if (resolvedValues != null) {
                try {
                    // 獲取構造方法的引數名稱(@ConstructorProperties 註解)
                    String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                    if (paramNames == null) {
                        // 沒有獲取到則通過 ParameterNameDiscoverer 引數探測器獲取引數名稱
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        if (pnd != null) {
                            paramNames = pnd.getParameterNames(candidate);
                        }
                    }
                    // 解析出方法的入參,引數值會被依賴注入
                    argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                            getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
                }
                catch (UnsatisfiedDependencyException ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
                    }
                    // Swallow and try next constructor.
                    if (causes == null) {
                        causes = new LinkedList<>();
                    }
                    causes.add(ex);
                    continue;
                }
            }
            // <5.1> 如果當前方法的入參指定了引數,如果個數相等則直接使用
            else {
                // Explicit arguments given -> arguments length must match exactly.
                if (paramTypes.length != explicitArgs.length) {
                    continue;
                }
                argsHolder = new ArgumentsHolder(explicitArgs);
            }

            // -------------------------根據權重獲取最匹配的方法-------------------------
            // <6> 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個

            // 判斷解析建構函式的時候是否以寬鬆模式還是嚴格模式,預設為 true
            // 嚴格模式:解析建構函式時,必須所有的都需要匹配,否則丟擲異常
            // 寬鬆模式:使用具有"最接近的模式"進行匹配
            // typeDiffWeight:型別差異權重
            int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                    argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
            // Choose this constructor if it represents the closest match.
            // 代表最匹配的結果,則選擇作為符合條件的方法
            if (typeDiffWeight < minTypeDiffWeight) {
                constructorToUse = candidate;
                argsHolderToUse = argsHolder;
                argsToUse = argsHolder.arguments;
                minTypeDiffWeight = typeDiffWeight;
                ambiguousConstructors = null;
            }
            else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet<>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }

        // <7> 沒有找到對應的構造方法,則丟擲異常
        if (constructorToUse == null) {
            if (causes != null) {
                UnsatisfiedDependencyException ex = causes.removeLast();
                for (Exception cause : causes) {
                    this.beanFactory.onSuppressedException(cause);
                }
                throw ex;
            }
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Could not resolve matching constructor " +
                    "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
        }
        else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Ambiguous constructor matches found in bean '" + beanName + "' " +
                    "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
                    ambiguousConstructors);
        }

        // <8> 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析
        if (explicitArgs == null && argsHolderToUse != null) {
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    Assert.state(argsToUse != null, "Unresolved constructor arguments");
    // <9> 呼叫這個構造方法返回一個例項物件(反射機制),並設定到 `bw` 中
    bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
    return bw;
}

這個方法我也是吐了?,不過還好,和上一個方法邏輯差不多,硬著頭皮,參考檔案:ConstructorResolver.java

對於過程不感興趣的可以跳過直接看下面的概括,過程大致如下:

先建立一個 BeanWrapperImpl 物件 bw,並初始化,設定 ConversionService 型別轉換器,並註冊自定義的屬性編輯器


  1. 嘗試獲取構造方法和入參

    1. 如果當前方法入參指定了引數,則直接使用

    2. 否則,嘗試從 RootBeanDefinition 中獲取已解析出來的構造方法和入參,如果獲取到了未被解析過的入參,則進行解析(型別轉換)

      例如給定方法 A(int, int),配置了 A("1"、"2") 兩個引數,則會轉換為 A(1, 1)

這一步嘗試獲取兩個物件:constructorToUse(構造方法)、argsToUse(構造方法的入參集合)


  1. 如果上一步沒有找到構造方法或入參集合,找到所有匹配的工廠方法,首先找到所有匹配的構造方法

    1. 獲取所有的構造方法,如果當前方法指定了構造方法的集合,則使用這個集合

    2. 如果構造方法只有一個,且當前方法的入參沒有指定引數,且本身也沒有定義引數,且這個構造方法沒有定義入參

      則直接呼叫這個構造方法建立一個例項物件(反射機制),並返回

上面第 2.2 步,通常只有預設構造方法才會直接呼叫並返回的,否則需要進行接下來的解析過程


  1. 確定構造引數的入引數量,匹配的方法的入引數量要多餘它
  2. 將所有的構造方法進行排序,public 方法優先,入參個數多的優先

這一步主要是確定入參的個數,並排序所有匹配的構造方法,接下來會遍歷所有匹配的構造方法


如果前面已經找到匹配的構造方法和入參,則直接結束迴圈;如果這個構造方法的引數個數小於入引數量,則跳過

  1. 解析出構造方法的入參
    1. 如果當前方法的入參指定了引數,如果個數相等則直接使用
    2. 否則,通過構造器注入獲取入參

這一步會找到這個構造方法的入參,構造器注入的方式


  1. 因為會遍歷所有匹配的方法,所以需要進行權重的判斷,拿到最優先的那個,會根據方法的引數型別進行權重

  1. 沒有找到對應的構造方法,則丟擲異常
  2. 將解析出來的工廠方法和入參快取,設定到 RootBeanDefinition 中,因為整個過程比較複雜,避免再次解析

會快取這幾個資料:resolvedConstructorOrFactoryMethod(已經解析出來的構造方法)、constructorArgumentsResolved(方法入參已經解析出來了 true)、resolvedConstructorArguments(解析出來的入參)


  1. 呼叫這個構造方法返回一個例項物件(反射機制),並設定到 bw

上面整個過程非常複雜,這裡進行簡單概括

  • 找到最匹配的構造方法

  • 如果構造方法有入參,則需要注入相關物件(構造器注入,其實也是依賴注入獲取到的引數)

  • 呼叫這個構造方法(反射機制),返回一個例項物件

instantiateBean 方法

兜底方法,如果構造方法找不到(或者已經解析出來的構造方法),則直接使用預設的構造方法(或者已經解析出來的構造方法),返回一個例項物件,方法如下:

// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        // 安全模式
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                    // 獲得 InstantiationStrategy 物件,並使用它,建立 Bean 物件
                    getInstantiationStrategy().instantiate(mbd, beanName, parent),
                    getAccessControlContext());
        }
        else {
             // 獲得 InstantiationStrategy 物件,並使用它,建立 Bean 物件
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

可以看到會通過 CglibSubclassingInstantiationStrategy#instantiate(...) 方法建立一個例項物件,該方法如下:

// SimpleInstantiationStrategy.java
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // Don't override the class with CGLIB if no overrides.
    // <1> 沒有 MethodOverride 物件,也就是沒有需要覆蓋或替換的方法,則直接使用反射機制進行例項化即可
    if (!bd.hasMethodOverrides()) {
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            // <1.1> 嘗試從 RootBeanDefinition 獲得已經解析出來的構造方法 `resolvedConstructorOrFactoryMethod`
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            // <1.2> 沒有解析出來的構造方法,則獲取預設的構造方法
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                // 如果是介面,丟擲 BeanInstantiationException 異常
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    // 從 clazz 中,獲得構造方法
                    if (System.getSecurityManager() != null) { // 安全模式
                        constructorToUse = AccessController.doPrivileged(
                                (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    }
                    else {
                        constructorToUse = clazz.getDeclaredConstructor();
                    }
                    // 標記 resolvedConstructorOrFactoryMethod 屬性
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        // <1.3> 通過這個構造方法例項化一個物件(反射機制)
        return BeanUtils.instantiateClass(constructorToUse);
    }
    // <2> 否則,通過 CGLIB 生成一個子類物件
    else {
        // Must generate CGLIB subclass.
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

過程大致如下:

  1. 沒有 MethodOverride 物件,也就是沒有需要覆蓋或替換的方法,則直接使用反射機制進行例項化即可
    1. 嘗試從 RootBeanDefinition 獲得已經解析出來的構造方法 resolvedConstructorOrFactoryMethod
    2. 沒有解析出來的構造方法,則獲取預設的構造方法
    3. 通過這個構造方法例項化一個物件(反射機制)
  2. 否則,通過 CGLIB 生成一個子類物件,該過程暫時忽略

整個過程並不複雜

總結

當我們顯示或者隱式地呼叫AbstractBeanFactorygetBean(...) 方法時,會觸發 Bean 的載入,在《開啟 Bean 的載入》文章中分析了整個載入過程。

對於不同作用域的 Bean,底層都會呼叫 AbstractAutowireCapableBeanFactorycreateBean(...) 方法進行建立,在上一篇《Bean 的建立過程》文章中分析了整個建立過程。在建立 Bean 的過程中,需要先建立一個例項物件,這個過程在例項化階段完成,主要分為下面幾種情況:

  1. 指定了 Supplier 例項化回撥介面,則回撥該介面,返回一個例項物件
  2. 配置了 factory-method 工廠方法建立當前 Bean,則找到這個方法,如果有入參,則需要找到對應的引數(依賴注入),然後建立一個例項物件(@Bean 註解底層原理也是這種方式)
  3. 找到一個最匹配的構造方法,如果有入參則需要找到對應的引數(構造器注入),返回一個例項物件,這個構造方法會設定到這個 RootBeanDefinition 中,避免再次解析,提高效能
  4. 兜底方法,使用預設構造方法返回一個例項物件

相關文章