【死磕 Spring】—– IOC 之構造函數實例化 bean

原文出自:http://cmsblogs.com

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() 方法中的第二個過程:屬性填充。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章