Spring IOC源码解析-创建原始bean对象

一.简介

这篇文章是之前一篇文章(创建单例bean的过程)的延续。在上篇文章中,从大体上讲述了doCreateBean方法的过程。今天,详细讲解下这个方法过程中的一个重要调用,即createBeanInstance方法。

二.源码分析

2.1 创建bean对象的过程

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

    /*
     * 检测类的访问权限。默认情况下,对于非 public 的类,是允许访问的。
     * 若禁止访问,这里会抛出异常
     */
    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());
    }

    /*
     * 如果工厂方法不为空,则通过工厂方法构建 
     */
    if (mbd.getFactoryMethodName() != null)  {
        // 通过“工厂方法”的方式构建 bean 对象
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    /*
     * 当多次构建同一个 bean 时,可以使用此处的快捷路径,即无需再次推断应该使用哪种方式构造实例,
     * 以提高效率。比如在多次构建同一个 prototype 类型的 bean 时,就可以走此处的捷径。
     * 这里的 resolved 和 mbd.constructorArgumentsResolved 将会在 bean 第一次实例
     * 化的过程中被设置。
     */
    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) {
            // 通过“构造方法自动注入”的方式构造 bean 对象
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 通过“默认构造方法”的方式构造 bean 对象
            return instantiateBean(beanName, mbd);
        }
    }

    // 由后置处理器决定返回哪些构造方法
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    /*
     * 下面的条件分支条件用于判断使用什么方式构造 bean 实例,有两种方式可选 - 构造方法自动
     * 注入和默认构造方法。判断的条件由4部分综合而成,如下:
     * 
     *    条件1:ctors != null -> 后置处理器返回构造方法数组是否为空
     *    
     *    条件2:mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR 
     *              -> bean 配置中的 autowire 属性是否为 constructor    
     *    条件3:mbd.hasConstructorArgumentValues() 
     *              -> constructorArgumentValues 是否存在元素,即 bean 配置文件中
     *                 是否配置了 <construct-arg/>
     *    条件4:!ObjectUtils.isEmpty(args) 
     *              -> args 数组是否存在元素,args 是由用户调用 
     *                 getBean(String name, Object... args) 传入的
     * 
     * 上面4个条件,只要有一个为 true,就会通过构造方法自动注入的方式构造 bean 实例
     */
    if (ctors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        // 通过“构造方法自动注入”的方式构造 bean 对象
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 通过“默认构造方法”的方式构造 bean 对象
    return instantiateBean(beanName, mbd);
}

这个方法的执行流程:

  1. 检测类的访问权限,若禁止访问,则抛出异常
  2. 如果在RootBeanDefinition中存在factoryMethodName属性,或者说在配置文件中配置了factory-method方法,那么对尝试使用instantiateUsingFactoryMethod(beanName, mbd, args)方法根据RootBeanDefinition中的配置生成bean的实例。
  3. 若构造方式已解析过,则走快捷路径构建 bean 对象,并返回结果。
  4. 如第三步不满足,则通过组合条件决定使用哪种方式构建 bean 对象。

在这个方法中体现了三种构造bean对象的方式,如下:

  1. 通过“工厂方法”的方式构造bean对象

  2. 通过“构造方法自动注入”的方式构造bean对象

  3. 通过“默认构造方法”的方式构造bean对象

接下来会详细介绍下这几种方式。

2.2 通过构造方法自动注入的方式创建bean实例

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

    // 创建 ConstructorResolver 对象,并调用其 autowireConstructor 方法
    return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}

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

    // 创建 BeanWrapperImpl 对象
    BeanWrapperImpl bw = new BeanWrapperImpl();
    this.beanFactory.initBeanWrapper(bw);

    Constructor<?> constructorToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;

    // 确定参数值列表(argsToUse)
    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) {
                    // 若 argsToUse 为空,则获取未解析的构造方法参数列表
                    argsToResolve = mbd.preparedConstructorArguments;
                }
            }
        }
        if (argsToResolve != null) {
            // 解析参数类型
            argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
        }
    }
  
 //上面总结为:构造参数不为空,直接使用;如果缓存中有已经解析的构造函数或者工厂方法,可以从缓存中获得构造参数参数。这个为空的话,从缓存中获得构造函数,然后通过构造函数获得构造参数类型。

   //如果缓存中构造器不存在,说明bean没有进行过解析
    if (constructorToUse == null) {
        //获得bean的构造器
        //如果传入的构造器不为空,获得注入方式
        boolean autowiring = (chosenCtors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
        ConstructorArgumentValues resolvedValues = null;

        int minNrOfArgs;
        if (explicitArgs != null) {
            minNrOfArgs = explicitArgs.length;
        }
        else {
             //从RootBeanDefinition中获取构造参数,并解析参数,添加到cargs
            ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
            resolvedValues = new ConstructorArgumentValues();
            /*
             * 确定构造方法参数数量,比如下面的配置:
             *     <bean id="persion" class="xyz.coolblog.autowire.Person">
             *         <constructor-arg index="0" value="xiaoming"/>
             *         <constructor-arg index="1" value="1"/>
             *         <constructor-arg index="2" value="man"/>
             *     </bean>
             *
             * 此时 minNrOfArgs = maxIndex + 1 = 2 + 1 = 3,除了计算 minNrOfArgs,
             * 下面的方法还会将 cargs 中的参数数据转存到 resolvedValues 中
             */
            minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
        }
   //这部分总结:获得注入方式和构造函数参数

        // 获取构造方法列表
        Constructor<?>[] candidates = chosenCtors;
        if (candidates == null) {
            //传入的构造器为空,获得bean的Class对象
            Class<?> beanClass = mbd.getBeanClass();
            try {
                //获取所有的构造器
                //getDeclaredConstructors:获得public和private修饰的
                //getConstructors:获得public修饰的
                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 分支的用途是:若匹配到到合适的构造方法了,提前结束 for 循环
             * constructorToUse != null 这个条件比较好理解,下面分析一下条件 argsToUse.length > paramTypes.length:
             * 前面说到 AutowireUtils.sortConstructors(candidates) 用于对构造方法进行
             * 排序,排序规则如下:
             *   1. 具有 public 访问权限的构造方法排在非 public 构造方法前
             *   2. 参数数量多的构造方法排在前面
             *
             * 假设现在有一组构造方法按照上面的排序规则进行排序,排序结果如下(省略参数名称):
             *
             *   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],可以匹配上的构造方法2和构造方法6。由于构造方法2有
             * 更高的访问权限,所以没理由不选他(尽管后者在参数类型上更加匹配)。由于构造方法3
             * 参数数量 < argsToUse.length,参数数量上不匹配,也不应该选。所以 
             * argsToUse.length > paramTypes.length 这个条件用途是:在条件 
             * constructorToUse != null 成立的情况下,通过判断参数数量与参数值数量
             * (argsToUse.length)是否一致,来决定是否提前终止构造方法匹配逻辑。
             */
            if (constructorToUse != null && argsToUse.length > paramTypes.length) {
                break;
            }

            /*
             * 构造方法参数数量低于配置的参数数量,则忽略当前构造方法,并重试。比如 
             * argsToUse = [obj1, obj2, obj3, obj4],上面的构造方法列表中,
             * 构造方法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) {
                            /*
                             * 获取构造方法参数名称列表,比如有这样一个构造方法:
                             *   public Person(String name, int age, String sex)
                             *   
                             * 调用 getParameterNames 方法返回 paramNames = [name, age, sex]
                             */
                            paramNames = pnd.getParameterNames(candidate);
                        }
                    }
               //上面是获得构造方法上的参数名称

                    /* 
                     * 创建参数值列表,返回 argsHolder 会包含进行类型转换后的参数值,比如下
                     * 面的配置:
                     *
                     *     <bean id="persion" class="xyz.coolblog.autowire.Person">
                     *         <constructor-arg name="name" value="xiaoming"/>
                     *         <constructor-arg name="age" value="1"/>
                     *         <constructor-arg name="sex" value="man"/>
                     *     </bean>
                     *
                     * Person 的成员变量 age 是 Integer 类型的,但由于在 Spring 配置中
                     * 只能配成 String 类型,所以这里要进行类型转换。
                     */
                   //根据已经获得参数类型,参数名称和构造参数类创建构造器用的构造参数数组
                    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<UnsatisfiedDependencyException>();
                    }
                    causes.add(ex);
                    continue;
                }
            }
            else {
                if (paramTypes.length != explicitArgs.length) {
                    continue;
                }
                argsHolder = new ArgumentsHolder(explicitArgs);
            }

            /*
             * 计算参数值(argsHolder.arguments)每个参数类型与构造方法参数列表
             * (paramTypes)中参数的类型差异量,差异量越大表明参数类型差异越大。参数类型差异
             * 越大,表明当前构造方法并不是一个最合适的候选项。引入差异量(typeDiffWeight)
             * 变量目的:是将候选构造方法的参数列表类型与参数值列表类型的差异进行量化,通过量化
             * 后的数值筛选出最合适的构造方法。
             * 
             * 讲完差异量,再来说说 mbd.isLenientConstructorResolution() 条件。
             * 官方的解释是:返回构造方法的解析模式,有宽松模式(lenient mode)和严格模式
             * 严格模式:构造解析函数时,必须所有进行匹配,否则抛出异常
             * 宽松模式:使用最接近的模式进行匹配              
             */
            int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                    argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
            if (typeDiffWeight < minTypeDiffWeight) {
                constructorToUse = candidate;
                argsHolderToUse = argsHolder;
                argsToUse = argsHolder.arguments;
                minTypeDiffWeight = typeDiffWeight;
                ambiguousConstructors = null;
            }
            /* 
             * 如果两个构造方法与参数值类型列表之间的差异量一致,那么这两个方法都可以作为
             * 候选项,这个时候就出现歧义了,这里先把有歧义的构造方法放入 
             * ambiguousConstructors 集合中
             */
            else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                if (ambiguousConstructors == null) {
                    ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
                    ambiguousConstructors.add(constructorToUse);
                }
                ambiguousConstructors.add(candidate);
            }
        }

        // 若上面未能筛选出合适的构造方法,这里将抛出 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 也不为空,表明解析
         * 出了多个的合适的构造方法,此时就出现歧义了。Spring 不会擅自决定使用哪个构造方法,
         * 所以抛出异常。
         */
        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) {
            /*
             * 缓存相关信息,比如:
             *   1. 已解析出的构造方法对象 resolvedConstructorOrFactoryMethod
             *   2. 构造方法参数列表是否已解析标志 constructorArgumentsResolved
             *   3. 参数值列表 resolvedConstructorArguments 或 preparedConstructorArguments
             *
             * 这些信息可用在其他地方,用于进行快捷判断
             */
            argsHolderToUse.storeCache(mbd, constructorToUse);
        }
    }

    try {
        Object beanInstance;

        if (System.getSecurityManager() != null) {
            final Constructor<?> ctorToUse = constructorToUse;
            final Object[] argumentsToUse = argsToUse;
            beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    return beanFactory.getInstantiationStrategy().instantiate(
                            mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
                }
            }, beanFactory.getAccessControlContext());
        }
        else {
            /*
             * 调用实例化策略创建实例,默认情况下使用反射创建实例。如果 bean 的配置信息中
             * 包含 lookup-method 和 replace-method,则通过 CGLIB 增强 bean 实例
             */
            beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
                    mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
        }

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

该方法的核心逻辑是根据参数值类型筛选合适的构造方法。解析出合适的构造方法后,剩下的工作就是构建 bean 对象了,这个工作交给了实例化策略去做。下面罗列一下这个方法的工作流程吧:

  1. 创建 BeanWrapperImpl 对象
  2. 构造函数参数的确定(有下面三种确定方式),并算出 minNrOfArgs。
    1. 根据explicitArgs参数判断。如果传入的这个参数不为空,可以直接确定参数。(因为explicitArgs参数是在调用Bean的时候用户指定的,在BeanFactory类中存在这样的方法:Object getBean(String name,Object... args) throws BeansException 在获取bean的时候,用户不但指定bean的名称还可以指定bean所对应类的构造函数或者工厂方法的参数,主要用于静态工厂方法的调用,而这里需要给定完全匹配的参数,所以,便可以判断,如果传入的参数explicitArgs不为空,则可以确定构造函数的参数就是它。)
    2. 缓存中获取。确定参数的办法之前如果已经分析过,也就是说构造函数参数已经记录在缓存中,那么便可以直接拿来使用。要注意的是,在缓存中缓存的可能是参数的最终类型也可能是参数的初始类型,例如:构造函数参数要求的是int类型,但是原始参数是String类型的,那么即便在缓存中得到了参数,也要经过类型转换器的过滤以确保参数类型域对应的构造函数参数类型完全对应。
    3. 配置文件的获取。以上两种情况都不可行的时候,分析从获取配置文件中配置的构造函数信息开始。可以通过调用 mbd.getConstructorArgumentValues()来获取配置的构造函数信息。有了配置中的信息就可以获取对应的参数值信息,获取参数值信息包括直接指定值。如:直接指定构造函数中某个值为原始类型String类型,或者是一个对其他bean的引用,而这一处理委托给resolvedConstructorArguments方法,并返回能解析到的参数的个数。
  3. 构造函数的确定,并排序。根据构造函数参数在所有构造函数中锁定对应的构造函数,而匹配的方法就是根据参数个数匹配,所以在匹配之前需要对构造函数按照public构造函数优先参数数量降序,非public构造函数优先参数数量降序。这样可以在遍历的情况下迅速判断排在后面的构造函数参数是否符合条件。
  4. 遍历排序好的构造方法列表,筛选合适的构造方法
    1. 获取构造方法参数列表中每个参数的名称。由于在配置文件中并不是唯一限制使用参数位置索引的方式去创建,同样还支持指定参数名称设定参数值的情况。一种是通过注解的方式直接获取,另一种就是使用Spring提供的工具类ParameterNameDiscoverer来获取。
    2. 再次解析参数,此次解析会将value 属性值进行类型转换,由 String 转为合适的类型。构造函数,参数名称,参数类型,参数值都可以确定后就可以锁定构造函数以及转换对应的参数类型。
    3. 计算构造方法参数列表与参数值列表之间的类型差异量,以筛选出更为合适的构造方法(构造函数不确定性的验证)。
  5. 缓存已筛选出的构造方法以及参数值列表,若再次创建 bean 实例时,可直接使用,无需再次进行筛选
  6. 使用初始化策略创建 bean 对象
  7. 将 bean 对象放入 BeanWrapperImpl 对象中,并返回该对象

2.3 通过默认构造方法创建 bean 对象

经历了带有参数的构造函数的实例构造,下来理解不带参数的构造函数实例化:

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        // if 条件分支里的一大坨是 Java 安全相关的代码,可以忽略,直接看 else 分支
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    return getInstantiationStrategy().instantiate(mbd, beanName, parent);
                }
            }, getAccessControlContext());
        }
        else {
            /*
             * 调用实例化策略创建实例,默认情况下使用反射创建对象。如果 bean 的配置信息中
             * 包含 lookup-method 和 replace-method,则通过 CGLIB 创建 bean 对象
             */
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        // 创建 BeanWrapperImpl 对象
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

2.4 实例化策略

经过前面的分析,我们已经得到了足够实例化的所有相关信息,完全可以使用最简单的反射方法直接反射来构造实例对象,但是Spring并没有这样做,而是调用了一个方法来实例化:

public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
    // 检测 bean 配置中是否配置了 lookup-method 或 replace-method,若配置了,则需使用 CGLIB 构建 bean 对象
    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<Constructor<?>>() {
                            @Override
                            public Constructor<?> run() throws Exception {
                                return clazz.getDeclaredConstructor((Class[]) null);
                            }
                        });
                    }
                    else {
                        // 获取默认构造方法
                        constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
                    }
                    // 设置 resolvedConstructorOrFactoryMethod
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        // 通过无参构造方法创建 bean 对象
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // 使用 GCLIG 创建 bean 对象
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

程序中,首先判断如果beanDefinition.getMethodOverrides()为空的话也就是用户没有使用lookup和replace的配置方法,那么直接使用反射方式,简单便捷,但是如果使用了这两个特性,就必须要使用动态代理的方式将包含两个特性对应的逻辑的拦截增强器设置进去,这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值包含拦截器的代理实例。

通过无参构造方法刚创建 bean 对象的代码:

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
    Assert.notNull(ctor, "Constructor must not be null");
    try {
        // 设置构造方法为可访问
        ReflectionUtils.makeAccessible(ctor);
        // 通过反射创建 bean 实例,这里的 args 是一个没有元素的空数组
        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());
    }
}

 

参考:创建原始 bean 对象

《Spring源码深度解析》

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