1. 程式人生 > >spring深入學習(二十) IOC 之建構函式例項化 bean

spring深入學習(二十) IOC 之建構函式例項化 bean

createBeanInstance() 用於例項化 bean,它會根據不同情況選擇不同的例項化策略來完成 bean 的初始化,主要包括:

  • Supplier 回撥:obtainFromSupplier()
  • 工廠方法初始化:instantiateUsingFactoryMethod()
  • 建構函式自動注入初始化:autowireConstructor()
  • 預設建構函式注入:instantiateBean()

在上篇部落格(【死磕 Spring】—– IOC 之 Factory 例項化 bean) 中分析了 Supplier 回撥和工廠方法初始化,這篇分析兩個建構函式注入。

autowireConstructor()

這個初始化方法我們可以簡單理解為是帶有引數的初始化 bean 。程式碼段如下:

   public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
                                           @Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {
        // 封裝 BeanWrapperImpl  並完成初始化
        BeanWrapperImpl bw = new BeanWrapperImpl();
        this.beanFactory.initBeanWrapper(bw);

        // 建構函式
        Constructor<?> constructorToUse = null;
        // 構造引數
        ArgumentsHolder argsHolderToUse = null;
        Object[] argsToUse = null;

        /*
         * 確定構造引數
         */
        // 如果 getBean() 已經傳遞,則直接使用
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        }
        else {

            /*
             *  嘗試從快取中獲取
             */
            Object[] argsToResolve = null;
            synchronized (mbd.constructorArgumentLock) {
                // 快取中的建構函式或者工廠方法
                constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                    // 快取中的構造引數
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }

            // 快取中存在,則解析儲存在 BeanDefinition 中的引數
            // 如給定方法的建構函式 A(int ,int ),則通過此方法後就會把配置檔案中的("1","1")轉換為 (1,1)
            // 快取中的值可能是原始值也有可能是最終值
            if (argsToResolve != null) {
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
            }
        }

        /*
         * 沒有快取,則嘗試從配置檔案中獲取
         */
        if (constructorToUse == null) {
            // 是否需要解析構造器
            boolean autowiring = (chosenCtors != null ||
                    mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);

            // 用於承載解析後的建構函式引數的值
            ConstructorArgumentValues resolvedValues = null;

            int minNrOfArgs;
            if (explicitArgs != null) {
                minNrOfArgs = explicitArgs.length;
            }
            else {
                // 從 BeanDefinition 中獲取構造引數,也就是從配置檔案中提取構造引數
                ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

                resolvedValues = new ConstructorArgumentValues();
                // 解析建構函式的引數
                // 將該 bean 的建構函式引數解析為 resolvedValues 物件,其中會涉及到其他 bean
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }

            /*
             * 獲取指定的建構函式
             */
            // 根據前面的判斷,chosenCtors 應該為 null
            Constructor<?>[] candidates = chosenCtors;
            if (candidates == null) {
                // 獲取 bean 的 class
                Class<?> beanClass = mbd.getBeanClass();
                try {
                    // 根據 class 獲取所有的建構函式
                    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);
                }
            }

            // 對建構函式進行排序處理
            // public 建構函式優先引數數量降序,非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.length > paramTypes.length) {
                    break;
                }
                // 引數個數不等,繼續
                if (paramTypes.length < minNrOfArgs) {
                    continue;
                }

                // 引數持有者
                ArgumentsHolder argsHolder;
                // 有引數
                if (resolvedValues != null) {
                    try {
                        // 註釋上獲取引數名稱
                        String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                        if (paramNames == null) {
                            // 獲取建構函式、方法引數的探測器
                            ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                            if (pnd != null) {
                                // 通過探測器獲取建構函式的引數名稱
                                paramNames = pnd.getParameterNames(candidate);
                            }
                        }

                        // 根據建構函式和構造引數建立引數持有者
                        argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                                getUserDeclaredConstructor(candidate), autowiring);
                    }
                    catch (UnsatisfiedDependencyException ex) {
                        if (this.beanFactory.logger.isTraceEnabled()) {
                            this.beanFactory.logger.trace(
                                    "Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
                        }
                        // Swallow and try next constructor.
                        if (causes == null) {
                            causes = new LinkedList<>();
                        }
                        causes.add(ex);
                        continue;
                    }
                }
                else {
                    // 建構函式沒有引數
                    if (paramTypes.length != explicitArgs.length) {
                        continue;
                    }
                    argsHolder = new ArgumentsHolder(explicitArgs);
                }

                // isLenientConstructorResolution 判斷解析建構函式的時候是否以寬鬆模式還是嚴格模式
                // 嚴格模式:解析建構函式時,必須所有的都需要匹配,否則丟擲異常
                // 寬鬆模式:使用具有"最接近的模式"進行匹配
                // typeDiffWeight:型別差異權重
                int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                        argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));

                // 如果它代表著當前最接近的匹配則選擇其作為建構函式
                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);
                }
            }

            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);
            }

            // 將建構函式、構造引數儲存到快取中
            if (explicitArgs == null) {
                argsHolderToUse.storeCache(mbd, constructorToUse);
            }
        }

        try {
            // 獲取建立 bean 的策略
            final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
            Object beanInstance;

            if (System.getSecurityManager() != null) {
                final Constructor<?> ctorToUse = constructorToUse;
                final Object[] argumentsToUse = argsToUse;
                // 例項化 bean
                beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                                strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
                        beanFactory.getAccessControlContext());
            }
            else {
                // 例項化bean
                beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
            }

            // 將構造的 bean 加入到 BeanWrapper 例項中
            bw.setBeanInstance(beanInstance);
            return bw;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean instantiation via constructor failed", ex);
        }
    }

程式碼與 instantiateUsingFactoryMethod() 一樣,又長又難懂,但是如果理解了 instantiateUsingFactoryMethod()初始化 bean 的過程,那麼 autowireConstructor() 也不存在什麼難的地方了,一句話概括:首先確定建構函式引數、建構函式,然後呼叫相應的初始化策略進行 bean 的初始化。關於如何確定建構函式、構造引數,該部分邏輯和 instantiateUsingFactoryMethod() 基本一致,所以這裡不再重複闡述了,具體過程請移步【死磕 Spring】—– IOC 之 Factory 例項化 bean

,這裡我們重點分析初始化策略。

對於初始化策略,首先是獲取例項化 bean 的策略,如下:

final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();

然後是呼叫其 instantiate()方法,該方法在 SimpleInstantiationStrategy 中實現,如下:

    public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        // 沒有覆蓋
        // 直接使用反射例項化即可
        if (!bd.hasMethodOverrides()) {
            // 重新檢測獲取下建構函式
            // 該建構函式是經過前面 N 多複雜過程確認的建構函式
            Constructor<?> constructorToUse;
            synchronized (bd.constructorArgumentLock) {
                // 獲取已經解析的建構函式
                constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                // 如果為 null,從 class 中解析獲取,並設定
                if (constructorToUse == null) {
                    final Class<?> clazz = bd.getBeanClass();
                    if (clazz.isInterface()) {
                        throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }
                    try {
                        if (System.getSecurityManager() != null) {
                            constructorToUse = AccessController.doPrivileged(
                                    (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                        }
                        else {
                            constructorToUse =  clazz.getDeclaredConstructor();
                        }
                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Throwable ex) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
                }
            }

            // 通過BeanUtils直接使用構造器物件例項化bean
            return BeanUtils.instantiateClass(constructorToUse);
        }
        else {
            // 生成CGLIB建立的子類物件
            return instantiateWithMethodInjection(bd, beanName, owner);
        }
    }

如果該 bean 沒有配置 lookup-method、replaced-method 標籤或者 @Lookup 註解,則直接通過反射的方式例項化 bean 即可,方便快捷,但是如果存在需要覆蓋的方法或者動態替換的方法則需要使用 CGLIB 進行動態代理,因為可以在建立代理的同時將動態方法織入類中。

反射

呼叫工具類 BeanUtils 的 instantiateClass() 方法完成反射工作:

    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
        Assert.notNull(ctor, "Constructor must not be null");
        try {
            ReflectionUtils.makeAccessible(ctor);
            return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                    KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
        }
        // 省略一些 catch 
    }

CGLIB

    protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
    }

方法預設是沒有實現的,具體過程由其子類 CglibSubclassingInstantiationStrategy 實現:

    protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
        return instantiateWithMethodInjection(bd, beanName, owner, null);
    }

    protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
            @Nullable Constructor<?> ctor, @Nullable Object... args) {

        // 通過CGLIB生成一個子類物件
        return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
    }

建立一個 CglibSubclassCreator 物件,呼叫其 instantiate() 方法生成其子類物件:

    public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) {
        // 通過 Cglib 建立一個代理類
        Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
        Object instance;
        // 沒有構造器,通過 BeanUtils 使用預設構造器建立一個bean例項
        if (ctor == null) {
            instance = BeanUtils.instantiateClass(subclass);
        }
        else {
            try {
                // 獲取代理類對應的構造器物件,並例項化 bean
                Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
                instance = enhancedSubclassConstructor.newInstance(args);
            }
            catch (Exception ex) {
                throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
                        "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
            }
        }

        // 為了避免memory leaks異常,直接在bean例項上設定回撥物件
        Factory factory = (Factory) instance;
        factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
                new CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
                new CglibSubclassingInstantiationStrategy.ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
        return instance;
    }

到這類 CGLIB 的方式分析完畢了,當然這裡還沒有具體分析 CGLIB 生成子類的詳細過程,具體的過程等後續分析 AOP 的時候再詳細地介紹。

instantiateBean()

   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>) () ->
                                getInstantiationStrategy().instantiate(mbd, beanName, parent),
                        getAccessControlContext());
            }
            else {
                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);
        }
    }

這個方法相比於 instantiateUsingFactoryMethod() 、 autowireConstructor() 方法實在是太簡單了,因為它沒有引數,所以不需要確認經過複雜的過來來確定構造器、構造引數,所以這裡就不過多闡述了。

對於 createBeanInstance() 而言,他就是選擇合適例項化策略來為 bean 建立例項物件,具體的策略有:Supplier 回撥方式、工廠方法初始化、建構函式自動注入初始化、預設建構函式注入。其中工廠方法初始化和建構函式自動注入初始化兩種方式最為複雜,主要是因為建構函式和構造引數的不確定性,Spring 需要花大量的精力來確定建構函式和構造引數,如果確定了則好辦,直接選擇例項化策略即可。當然在例項化的時候會根據是否有需要覆蓋或者動態替換掉的方法,因為存在覆蓋或者織入的話需要建立動態代理將方法織入,這個時候就只能選擇 CGLIB 的方式來例項化,否則直接利用反射的方式即可,方便快捷。

到這裡 createBeanInstance() 的過程就已經分析完畢了,下篇介紹 doCreateBean() 方法中的第二個過程:屬性填充。