成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Spring IOC 容器源碼分析 - 創(chuàng)建原始 bean 對(duì)象

sutaking / 1445人閱讀

摘要:你也會(huì)了解到構(gòu)造對(duì)象的兩種策略。構(gòu)造方法參數(shù)數(shù)量低于配置的參數(shù)數(shù)量,則忽略當(dāng)前構(gòu)造方法,并重試。通過默認(rèn)構(gòu)造方法創(chuàng)建對(duì)象看完了上面冗長(zhǎng)的邏輯,本節(jié)來看點(diǎn)輕松的吧通過默認(rèn)構(gòu)造方法創(chuàng)建對(duì)象。

1. 簡(jiǎn)介

本篇文章是上一篇文章(創(chuàng)建單例 bean 的過程)的延續(xù)。在上一篇文章中,我們從戰(zhàn)略層面上領(lǐng)略了doCreateBean方法的全過程。本篇文章,我們就從戰(zhàn)術(shù)的層面上,詳細(xì)分析doCreateBean方法中的一個(gè)重要的調(diào)用,即createBeanInstance方法。在本篇文章中,你將看到三種不同的構(gòu)造 bean 對(duì)象的方式。你也會(huì)了解到構(gòu)造 bean 對(duì)象的兩種策略。如果你對(duì)這些內(nèi)容感興趣,那么不妨繼續(xù)往下讀。我會(huì)在代碼進(jìn)行大量的注解,相信能幫助你理解代碼邏輯。好了,其他的就不多說了,進(jìn)入正題吧。

2. 源碼分析 2.1 創(chuàng)建 bean 對(duì)象的過程

本節(jié),我們一起來來分析一下本篇文章的主角createBeanInstance方法。按照慣例,我們還是先分析一下方法的大致脈絡(luò),然后我們?cè)侔凑者@個(gè)脈絡(luò)去分析一些重要的調(diào)用。So. Let`s go → ↓

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    Class beanClass = resolveBeanClass(mbd, beanName);

    /*
     * 檢測(cè)類的訪問權(quán)限。默認(rèn)情況下,對(duì)于非 public 的類,是允許訪問的。
     * 若禁止訪問,這里會(huì)拋出異常
     */
    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());
    }

    /*
     * 如果工廠方法不為空,則通過工廠方法構(gòu)建 bean 對(duì)象。這種構(gòu)建 bean 的方式
     * 就不深入分析了,有興趣的朋友可以自己去看一下。
     */
    if (mbd.getFactoryMethodName() != null)  {
        // 通過“工廠方法”的方式構(gòu)建 bean 對(duì)象
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    /*
     * 當(dāng)多次構(gòu)建同一個(gè) bean 時(shí),可以使用此處的快捷路徑,即無需再次推斷應(yīng)該使用哪種方式構(gòu)造實(shí)例,
     * 以提高效率。比如在多次構(gòu)建同一個(gè) prototype 類型的 bean 時(shí),就可以走此處的捷徑。
     * 這里的 resolved 和 mbd.constructorArgumentsResolved 將會(huì)在 bean 第一次實(shí)例
     * 化的過程中被設(shè)置,在后面的源碼中會(huì)分析到,先繼續(xù)往下看。
     */
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            // 通過“構(gòu)造方法自動(dòng)注入”的方式構(gòu)造 bean 對(duì)象
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 通過“默認(rèn)構(gòu)造方法”的方式構(gòu)造 bean 對(duì)象
            return instantiateBean(beanName, mbd);
        }
    }

    // 由后置處理器決定返回哪些構(gòu)造方法,這里不深入分析了
    Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    /*
     * 下面的條件分支條件用于判斷使用什么方式構(gòu)造 bean 實(shí)例,有兩種方式可選 - 構(gòu)造方法自動(dòng)
     * 注入和默認(rèn)構(gòu)造方法。判斷的條件由4部分綜合而成,如下:
     * 
     *    條件1:ctors != null -> 后置處理器返回構(gòu)造方法數(shù)組是否為空
     *    
     *    條件2:mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR 
     *              -> bean 配置中的 autowire 屬性是否為 constructor    
     *    條件3:mbd.hasConstructorArgumentValues() 
     *              -> constructorArgumentValues 是否存在元素,即 bean 配置文件中
     *                 是否配置了 
     *    條件4:!ObjectUtils.isEmpty(args) 
     *              -> args 數(shù)組是否存在元素,args 是由用戶調(diào)用 
     *                 getBean(String name, Object... args) 傳入的
     * 
     * 上面4個(gè)條件,只要有一個(gè)為 true,就會(huì)通過構(gòu)造方法自動(dòng)注入的方式構(gòu)造 bean 實(shí)例
     */
    if (ctors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        // 通過“構(gòu)造方法自動(dòng)注入”的方式構(gòu)造 bean 對(duì)象
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 通過“默認(rèn)構(gòu)造方法”的方式構(gòu)造 bean 對(duì)象
    return instantiateBean(beanName, mbd);
}

以上就是 createBeanInstance 方法的源碼,不是很長(zhǎng)。配合著注釋,應(yīng)該不是很難懂。下面我們來總結(jié)一下這個(gè)方法的執(zhí)行流程,如下:

檢測(cè)類的訪問權(quán)限,若禁止訪問,則拋出異常

若工廠方法不為空,則通過工廠方法構(gòu)建 bean 對(duì)象,并返回結(jié)果

若構(gòu)造方式已解析過,則走快捷路徑構(gòu)建 bean 對(duì)象,并返回結(jié)果

如第三步不滿足,則通過組合條件決定使用哪種方式構(gòu)建 bean 對(duì)象

這里有三種構(gòu)造 bean 對(duì)象的方式,如下:

通過“工廠方法”的方式構(gòu)造 bean 對(duì)象

通過“構(gòu)造方法自動(dòng)注入”的方式構(gòu)造 bean 對(duì)象

通過“默認(rèn)構(gòu)造方法”的方式構(gòu)造 bean 對(duì)象

下面我將會(huì)分析第2和第3種構(gòu)造 bean 對(duì)象方式的實(shí)現(xiàn)源碼。至于第1種方式,實(shí)現(xiàn)邏輯和第2種方式較為相似。所以就不分析了,大家有興趣可以自己看一下。

2.2 通過構(gòu)造方法自動(dòng)注入的方式創(chuàng)建 bean 實(shí)例

本節(jié),我將會(huì)分析構(gòu)造方法自動(dòng)注入的實(shí)現(xiàn)邏輯。代碼邏輯較為復(fù)雜,需要大家耐心閱讀。代碼如下:

protected BeanWrapper autowireConstructor(
        String beanName, RootBeanDefinition mbd, Constructor[] ctors, Object[] explicitArgs) {

    // 創(chuàng)建 ConstructorResolver 對(duì)象,并調(diào)用其 autowireConstructor 方法
    return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
        Constructor[] chosenCtors, final Object[] explicitArgs) {

    // 創(chuàng)建 BeanWrapperImpl 對(duì)象
    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);

    Constructor constructorToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;

    // 確定參數(shù)值列表(argsToUse)
    if (explicitArgs != null) {
        argsToUse = explicitArgs;
    }
    else {
        Object[] argsToResolve = null;
        synchronized (mbd.constructorArgumentLock) {
            // 獲取已解析的構(gòu)造方法
            constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                // 獲取已解析的構(gòu)造方法參數(shù)列表
                argsToUse = mbd.resolvedConstructorArguments;
                if (argsToUse == null) {
                    // 若 argsToUse 為空,則獲取未解析的構(gòu)造方法參數(shù)列表
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        if (argsToResolve != null) {
            // 解析參數(shù)列表
            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 {
            ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
            resolvedValues = new ConstructorArgumentValues();
            /*
             * 確定構(gòu)造方法參數(shù)數(shù)量,比如下面的配置:
             *     
             *         
             *         
             *         
             *     
             *
             * 此時(shí) minNrOfArgs = maxIndex + 1 = 2 + 1 = 3,除了計(jì)算 minNrOfArgs,
             * 下面的方法還會(huì)將 cargs 中的參數(shù)數(shù)據(jù)轉(zhuǎn)存到 resolvedValues 中
             */
            minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
        }

        // 獲取構(gòu)造方法列表
        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);
            }
        }

        // 按照構(gòu)造方法的訪問權(quán)限級(jí)別和參數(shù)數(shù)量進(jìn)行排序
        AutowireUtils.sortConstructors(candidates);

        int minTypeDiffWeight = Integer.MAX_VALUE;
        Set> ambiguousConstructors = null;
        LinkedList causes = null;

        for (Constructor candidate : candidates) {
            Class[] paramTypes = candidate.getParameterTypes();

            /*
             * 下面的 if 分支的用途是:若匹配到到合適的構(gòu)造方法了,提前結(jié)束 for 循環(huán)
             * constructorToUse != null 這個(gè)條件比較好理解,下面分析一下條件 argsToUse.length > paramTypes.length:
             * 前面說到 AutowireUtils.sortConstructors(candidates) 用于對(duì)構(gòu)造方法進(jìn)行
             * 排序,排序規(guī)則如下:
             *   1. 具有 public 訪問權(quán)限的構(gòu)造方法排在非 public 構(gòu)造方法前
             *   2. 參數(shù)數(shù)量多的構(gòu)造方法排在前面
             *
             * 假設(shè)現(xiàn)在有一組構(gòu)造方法按照上面的排序規(guī)則進(jìn)行排序,排序結(jié)果如下(省略參數(shù)名稱):
             *
             *   1. public Hello(Object, Object, Object)
             *   2. public Hello(Object, Object)
             *   3. public Hello(Object)
             *   4. protected Hello(Integer, Object, Object, Object)
             *   5. protected Hello(Integer, Object, Object)
             *   6. protected Hello(Integer, Object)
             *
             * argsToUse = [num1, obj2],可以匹配上的構(gòu)造方法2和構(gòu)造方法6。由于構(gòu)造方法2有
             * 更高的訪問權(quán)限,所以沒理由不選他(盡管后者在參數(shù)類型上更加匹配)。由于構(gòu)造方法3
             * 參數(shù)數(shù)量 < argsToUse.length,參數(shù)數(shù)量上不匹配,也不應(yīng)該選。所以 
             * argsToUse.length > paramTypes.length 這個(gè)條件用途是:在條件 
             * constructorToUse != null 成立的情況下,通過判斷參數(shù)數(shù)量與參數(shù)值數(shù)量
             * (argsToUse.length)是否一致,來決定是否提前終止構(gòu)造方法匹配邏輯。
             */
            if (constructorToUse != null && argsToUse.length > paramTypes.length) {
                break;
            }

            /*
             * 構(gòu)造方法參數(shù)數(shù)量低于配置的參數(shù)數(shù)量,則忽略當(dāng)前構(gòu)造方法,并重試。比如 
             * argsToUse = [obj1, obj2, obj3, obj4],上面的構(gòu)造方法列表中,
             * 構(gòu)造方法1、2和3顯然不是合適選擇,忽略之。
             */
            if (paramTypes.length < minNrOfArgs) {
                continue;
            }

            ArgumentsHolder argsHolder;
            if (resolvedValues != null) {
                try {
                    /*
                     * 判斷否則方法是否有 ConstructorProperties 注解,若有,則取注解中的
                     * 值。比如下面的代碼:
                     * 
                     *  public class Persion {
                     *      private String name;
                     *      private Integer age;
                     *
                     *      @ConstructorProperties(value = {"coolblog", "20"})
                     *      public Persion(String name, Integer age) {
                     *          this.name = name;
                     *          this.age = age;
                     *      }
                     * }
                     */
                    String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
                    if (paramNames == null) {
                        ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                        if (pnd != null) {
                            /*
                             * 獲取構(gòu)造方法參數(shù)名稱列表,比如有這樣一個(gè)構(gòu)造方法:
                             *   public Person(String name, int age, String sex)
                             *   
                             * 調(diào)用 getParameterNames 方法返回 paramNames = [name, age, sex]
                             */
                            paramNames = pnd.getParameterNames(candidate);
                        }
                    }

                    /* 
                     * 創(chuàng)建參數(shù)值列表,返回 argsHolder 會(huì)包含進(jìn)行類型轉(zhuǎn)換后的參數(shù)值,比如下
                     * 面的配置:
                     *
                     *     
                     *         
                     *         
                     *         
                     *     
                     *
                     * Person 的成員變量 age 是 Integer 類型的,但由于在 Spring 配置中
                     * 只能配成 String 類型,所以這里要進(jìn)行類型轉(zhuǎn)換。
                     */
                    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);
                    }
                    if (causes == null) {
                        causes = new LinkedList();
                    }
                    causes.add(ex);
                    continue;
                }
            }
            else {
                if (paramTypes.length != explicitArgs.length) {
                    continue;
                }
                argsHolder = new ArgumentsHolder(explicitArgs);
            }

            /*
             * 計(jì)算參數(shù)值(argsHolder.arguments)每個(gè)參數(shù)類型與構(gòu)造方法參數(shù)列表
             * (paramTypes)中參數(shù)的類型差異量,差異量越大表明參數(shù)類型差異越大。參數(shù)類型差異
             * 越大,表明當(dāng)前構(gòu)造方法并不是一個(gè)最合適的候選項(xiàng)。引入差異量(typeDiffWeight)
             * 變量目的:是將候選構(gòu)造方法的參數(shù)列表類型與參數(shù)值列表類型的差異進(jìn)行量化,通過量化
             * 后的數(shù)值篩選出最合適的構(gòu)造方法。
             * 
             * 講完差異量,再來說說 mbd.isLenientConstructorResolution() 條件。
             * 官方的解釋是:返回構(gòu)造方法的解析模式,有寬松模式(lenient mode)和嚴(yán)格模式
             * (strict mode)兩種類型可選。具體的細(xì)節(jié)沒去研究,就不多說了。
             */
            int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                    argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
            if (typeDiffWeight < minTypeDiffWeight) {
                constructorToUse = candidate;
                argsHolderToUse = argsHolder;
                argsToUse = argsHolder.arguments;
                minTypeDiffWeight = typeDiffWeight;
                ambiguousConstructors = null;
            }
            /* 
             * 如果兩個(gè)構(gòu)造方法與參數(shù)值類型列表之間的差異量一致,那么這兩個(gè)方法都可以作為
             * 候選項(xiàng),這個(gè)時(shí)候就出現(xiàn)歧義了,這里先把有歧義的構(gòu)造方法放入 
             * ambiguousConstructors 集合中
             */
            else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }

        // 若上面未能篩選出合適的構(gòu)造方法,這里將拋出 BeanCreationException 異常
        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)");
        }
        /*
         * 如果 constructorToUse != null,且 ambiguousConstructors 也不為空,表明解析
         * 出了多個(gè)的合適的構(gòu)造方法,此時(shí)就出現(xiàn)歧義了。Spring 不會(huì)擅自決定使用哪個(gè)構(gòu)造方法,
         * 所以拋出異常。
         */
        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) {
            /*
             * 緩存相關(guān)信息,比如:
             *   1. 已解析出的構(gòu)造方法對(duì)象 resolvedConstructorOrFactoryMethod
             *   2. 構(gòu)造方法參數(shù)列表是否已解析標(biāo)志 constructorArgumentsResolved
             *   3. 參數(shù)值列表 resolvedConstructorArguments 或 preparedConstructorArguments
             *
             * 這些信息可用在其他地方,用于進(jìn)行快捷判斷
             */
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    try {
        Object beanInstance;

        if (System.getSecurityManager() != null) {
            final Constructor ctorToUse = constructorToUse;
            final Object[] argumentsToUse = argsToUse;
            beanInstance = AccessController.doPrivileged(new PrivilegedAction() {
                @Override
                public Object run() {
                    return beanFactory.getInstantiationStrategy().instantiate(
                            mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
                }
            }, beanFactory.getAccessControlContext());
        }
        else {
            /*
             * 調(diào)用實(shí)例化策略創(chuàng)建實(shí)例,默認(rèn)情況下使用反射創(chuàng)建實(shí)例。如果 bean 的配置信息中
             * 包含 lookup-method 和 replace-method,則通過 CGLIB 增強(qiáng) bean 實(shí)例
             */
            beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
                    mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
        }

        // 設(shè)置 beanInstance 到 BeanWrapperImpl 對(duì)象中
        bw.setBeanInstance(beanInstance);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean instantiation via constructor failed", ex);
    }
}

上面的方法邏輯比較復(fù)雜,做了不少事情,該方法的核心邏輯是根據(jù)參數(shù)值類型篩選合適的構(gòu)造方法。解析出合適的構(gòu)造方法后,剩下的工作就是構(gòu)建 bean 對(duì)象了,這個(gè)工作交給了實(shí)例化策略去做。下面羅列一下這個(gè)方法的工作流程吧:

創(chuàng)建 BeanWrapperImpl 對(duì)象

解析構(gòu)造方法參數(shù),并算出 minNrOfArgs

獲取構(gòu)造方法列表,并排序

遍歷排序好的構(gòu)造方法列表,篩選合適的構(gòu)造方法

獲取構(gòu)造方法參數(shù)列表中每個(gè)參數(shù)的名稱

再次解析參數(shù),此次解析會(huì)將 value 屬性值進(jìn)行類型轉(zhuǎn)換,由 String 轉(zhuǎn)為合適的類型。

計(jì)算構(gòu)造方法參數(shù)列表與參數(shù)值列表之間的類型差異量,以篩選出更為合適的構(gòu)造方法

緩存已篩選出的構(gòu)造方法以及參數(shù)值列表,若再次創(chuàng)建 bean 實(shí)例時(shí),可直接使用,無需再次進(jìn)行篩選

使用初始化策略創(chuàng)建 bean 對(duì)象

將 bean 對(duì)象放入 BeanWrapperImpl 對(duì)象中,并返回該對(duì)象

由上面的流程可以看得出,通過構(gòu)造方法自動(dòng)注入的方式構(gòu)造 bean 對(duì)象的過程還是很復(fù)雜的。為了看懂這個(gè)流程,我進(jìn)行了多次調(diào)試,算是勉強(qiáng)弄懂大致邏輯。由于時(shí)間有限,我并未能詳細(xì)分析 autowireConstructor 方法及其所調(diào)用的一些方法,比如 resolveConstructorArguments、 autowireConstructor 等。關(guān)于這些方法,這里只寫了個(gè)大概,有興趣的朋友自己去探索吧。

2.3 通過默認(rèn)構(gòu)造方法創(chuàng)建 bean 對(duì)象

看完了上面冗長(zhǎng)的邏輯,本節(jié)來看點(diǎn)輕松的吧 - 通過默認(rèn)構(gòu)造方法創(chuàng)建 bean 對(duì)象。如下:

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        // if 條件分支里的一大坨是 Java 安全相關(guān)的代碼,可以忽略,直接看 else 分支
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged(new PrivilegedAction() {
                @Override
                public Object run() {
                    return getInstantiationStrategy().instantiate(mbd, beanName, parent);
                }
            }, getAccessControlContext());
        }
        else {
            /*
             * 調(diào)用實(shí)例化策略創(chuàng)建實(shí)例,默認(rèn)情況下使用反射創(chuàng)建對(duì)象。如果 bean 的配置信息中
             * 包含 lookup-method 和 replace-method,則通過 CGLIB 創(chuàng)建 bean 對(duì)象
             */
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        // 創(chuàng)建 BeanWrapperImpl 對(duì)象
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
    // 檢測(cè) bean 配置中是否配置了 lookup-method 或 replace-method,若配置了,則需使用 CGLIB 構(gòu)建 bean 對(duì)象
    if (bd.getMethodOverrides().isEmpty()) {
        Constructor constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            constructorToUse = (Constructor) bd.resolvedConstructorOrFactoryMethod;
            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(new PrivilegedExceptionAction>() {
                            @Override
                            public Constructor run() throws Exception {
                                return clazz.getDeclaredConstructor((Class[]) null);
                            }
                        });
                    }
                    else {
                        // 獲取默認(rèn)構(gòu)造方法
                        constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
                    }
                    // 設(shè)置 resolvedConstructorOrFactoryMethod
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        // 通過無參構(gòu)造方法創(chuàng)建 bean 對(duì)象
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // 使用 GCLIG 創(chuàng)建 bean 對(duì)象
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

上面就是通過默認(rèn)構(gòu)造方法創(chuàng)建 bean 對(duì)象的過程,比較簡(jiǎn)單,就不多說了。最后我們?cè)賮砜纯春?jiǎn)單看看通過無參構(gòu)造方法剛創(chuàng)建 bean 對(duì)象的代碼(通過 CGLIB 創(chuàng)建 bean 對(duì)象的方式就不看了)是怎樣的,如下:

public static  T instantiateClass(Constructor ctor, Object... args) throws BeanInstantiationException {
    Assert.notNull(ctor, "Constructor must not be null");
    try {
        // 設(shè)置構(gòu)造方法為可訪問
        ReflectionUtils.makeAccessible(ctor);
        // 通過反射創(chuàng)建 bean 實(shí)例,這里的 args 是一個(gè)沒有元素的空數(shù)組
        return ctor.newInstance(args);
    }
    catch (InstantiationException ex) {
        throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
    }
    catch (IllegalAccessException ex) {
        throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
    }
    catch (IllegalArgumentException ex) {
        throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
    }
    catch (InvocationTargetException ex) {
        throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
    }
}

到這里,終于看到了創(chuàng)建 bean 對(duì)象的代碼了。在經(jīng)歷層層調(diào)用后,我們總算是追到了調(diào)用棧的最深處??吹竭@里,大家可以休息一下了,本文也差不多要結(jié)束了。好了,最后再容我多啰嗦一會(huì),往下看。

3.寫在最后

寫到這里,我也算是松了一口氣,終于快寫完了。這篇文章寫起來感覺挺不容易的,原因是 createBeanInstance 及其調(diào)用的方法是在太多了,而且很多方法邏輯還是比較復(fù)雜的,尤其是 autowireConstructor 中調(diào)用的一些方法。autowireConstructor 中調(diào)用的方法我基本上都看了一遍,但并非全部都弄懂了,有些方法只是知道個(gè)大概。所以,這篇文章寫的我挺糾結(jié)的,生怕有些地方分析的不對(duì)。由于我后續(xù)還有很多東西要看,以至于我暫時(shí)沒法抽出大量的時(shí)間去詳細(xì)閱讀 Spring 的源碼。所以如果上面的分析有不對(duì)的地方,歡迎指正,我會(huì)虛心聽之。如果這些不對(duì)的地方給你造成了困擾,實(shí)在很抱歉,抱歉。

好了,本篇文章先到這里。謝謝閱讀!

參考

《Spring 源碼深度解析》- 郝佳

附錄:Spring 源碼分析文章列表 Ⅰ. IOC
更新時(shí)間 標(biāo)題
2018-05-30 Spring IOC 容器源碼分析系列文章導(dǎo)讀
2018-06-01 Spring IOC 容器源碼分析 - 獲取單例 bean
2018-06-04 Spring IOC 容器源碼分析 - 創(chuàng)建單例 bean 的過程
2018-06-06 Spring IOC 容器源碼分析 - 創(chuàng)建原始 bean 對(duì)象
2018-06-08 Spring IOC 容器源碼分析 - 循環(huán)依賴的解決辦法
2018-06-11 Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對(duì)象
2018-06-11 Spring IOC 容器源碼分析 - 余下的初始化工作
Ⅱ. AOP
更新時(shí)間 標(biāo)題
2018-06-17 Spring AOP 源碼分析系列文章導(dǎo)讀
2018-06-20 Spring AOP 源碼分析 - 篩選合適的通知器
2018-06-20 Spring AOP 源碼分析 - 創(chuàng)建代理對(duì)象
2018-06-22 Spring AOP 源碼分析 - 攔截器鏈的執(zhí)行過程
Ⅲ. MVC
更新時(shí)間 標(biāo)題
2018-06-29 Spring MVC 原理探秘 - 一個(gè)請(qǐng)求的旅行過程
2018-06-30 Spring MVC 原理探秘 - 容器的創(chuàng)建過程
本文在知識(shí)共享許可協(xié)議 4.0 下發(fā)布,轉(zhuǎn)載需在明顯位置處注明出處
作者:coolblog.xyz
本文同步發(fā)布在我的個(gè)人博客:http://www.coolblog.xyz


本作品采用知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議進(jìn)行許可。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69664.html

相關(guān)文章

  • Spring IOC 容器源碼分析 - 循環(huán)依賴的解決辦法

    摘要:實(shí)例化時(shí),發(fā)現(xiàn)又依賴于。一些緩存的介紹在進(jìn)行源碼分析前,我們先來看一組緩存的定義??墒强赐暝创a后,我們似乎仍然不知道這些源碼是如何解決循環(huán)依賴問題的。 1. 簡(jiǎn)介 本文,我們來看一下 Spring 是如何解決循環(huán)依賴問題的。在本篇文章中,我會(huì)首先向大家介紹一下什么是循環(huán)依賴。然后,進(jìn)入源碼分析階段。為了更好的說明 Spring 解決循環(huán)依賴的辦法,我將會(huì)從獲取 bean 的方法getB...

    aikin 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析 - 余下的初始化工作

    摘要:簡(jiǎn)介本篇文章是容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對(duì)象是方法,該方法用于對(duì)已完成屬性填充的做最后的初始化工作。后置處理器是拓展點(diǎn)之一,通過實(shí)現(xiàn)后置處理器接口,我們就可以插手的初始化過程。 1. 簡(jiǎn)介 本篇文章是Spring IOC 容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對(duì)象是 initializeBean 方法,該方法用于對(duì)已完成屬性填充的 bean 做最...

    Alfred 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析系列文章導(dǎo)讀

    摘要:本文是容器源碼分析系列文章的第一篇文章,將會(huì)著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過這兩個(gè)別名獲取到這個(gè)實(shí)例,比如下面的測(cè)試代碼測(cè)試結(jié)果如下本小節(jié),我們來了解一下這個(gè)特性。 1. 簡(jiǎn)介 Spring 是一個(gè)輕量級(jí)的企業(yè)級(jí)應(yīng)用開發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...

    NSFish 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析 - 填充屬性到 bean 原始對(duì)象

    摘要:源碼分析源碼一覽本節(jié),我們先來看一下填充屬性的方法,即。所有的屬性值是在方法中統(tǒng)一被注入到對(duì)象中的。檢測(cè)是否存在與相關(guān)的或。這樣可以在很大程度上降低源碼分析的難度。若候選項(xiàng)是非類型,則表明已經(jīng)完成了實(shí)例化,此時(shí)直接返回即可。 1. 簡(jiǎn)介 本篇文章,我們來一起了解一下 Spring 是如何將配置文件中的屬性值填充到 bean 對(duì)象中的。我在前面幾篇文章中介紹過 Spring 創(chuàng)建 bea...

    SKYZACK 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析 - 創(chuàng)建單例 bean 的過程

    摘要:關(guān)于創(chuàng)建實(shí)例的過程,我將會(huì)分幾篇文章進(jìn)行分析。源碼分析創(chuàng)建實(shí)例的入口在正式分析方法前,我們先來看看方法是在哪里被調(diào)用的。時(shí),表明方法不存在,此時(shí)拋出異常。該變量用于表示是否提前暴露單例,用于解決循環(huán)依賴。 1. 簡(jiǎn)介 在上一篇文章中,我比較詳細(xì)的分析了獲取 bean 的方法,也就是getBean(String)的實(shí)現(xiàn)邏輯。對(duì)于已實(shí)例化好的單例 bean,getBean(String) ...

    mochixuan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<