专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

【spring源码分析】IOC容器初始化(九)

前言:上篇文章末尾提到createBeanInstance方法中使用工厂方法实例化Bean对象,本文将对该方法进行分析。


AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod

     protected BeanWrapper instantiateUsingFactoryMethod(
             String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

         return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
     }

可以看到这里是委托给ConstructorResolver来实现的:

 // ConstructorResolver
 public BeanWrapper instantiateUsingFactoryMethod(
             String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
         // 构造BeanWrapperImpl对象
         BeanWrapperImpl bw = new BeanWrapperImpl();
         // 初始化BeanWrapperImpl 向BeanWrapper对象中添加ConversionService对象和属性编辑器PropertyEditor对象
         this.beanFactory.initBeanWrapper(bw);

         // 获得factoryBean、factoryClass、isStatic、factoryBeanName属性
         Object factoryBean;
         Class<?> factoryClass;
         boolean isStatic;

         String factoryBeanName = mbd.getFactoryBeanName();
         // 工厂名不为空
         if (factoryBeanName != null) {
             // 如果工厂名和beanName相等,则抛出BeanDefinitionStoreException异常
             if (factoryBeanName.equals(beanName)) {
                 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                                                        "factory-bean reference points back to the same bean definition");
             }
             // 获取工厂实例
             factoryBean = this.beanFactory.getBean(factoryBeanName);
             // 如果是单例模式,并且已经缓存中已经存在beanName则抛出异常
             if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
                 throw new ImplicitlyAppearedSingletonException();
             }
             factoryClass = factoryBean.getClass();
             isStatic = false;
         } else {
             // 工厂名为空,则其可能是一个静态工厂
             // 静态工厂创建bean,必须要提供工厂的全类名
             // It's a static factory method on the bean 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;
         }

         // 获得factoryMethodToUse、argsHolderToUse、argsToUse属性
         Method factoryMethodToUse = null;
         ArgumentsHolder argsHolderToUse = null;
         Object[] argsToUse = null;

         // 如果指定了构造参数则直接使用
         // 在调用getBean方法的时候指定方法参数
         if (explicitArgs != null) {
             argsToUse = explicitArgs;
         } 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) {
                         argsToResolve = mbd.preparedConstructorArguments;
                     }
                 }
             }
             // 缓存中存在,则解析存储在BeanDefinition中的参数
             // 如给定方法的构造函数 f(int ,int),通过此方法后就会把配置文件中的("1","1")转换为(1,1)
             // 缓存中的值可能是原始值,也可能是最终值
             if (argsToResolve != null) {
                 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
             }
         }

         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.
             // 获取工厂方法的类的全类名
             factoryClass = ClassUtils.getUserClass(factoryClass);

             List<Method> candidateList = null;
             // 同步
             if (mbd.isFactoryMethodUnique) {
                 // 获取工厂方法
                 if (factoryMethodToUse == null) {
                     factoryMethodToUse = mbd.getResolvedFactoryMethod();
                 }
                 // 获取所有待定的工厂方法
                 if (factoryMethodToUse != null) {
                     candidateList = Collections.singletonList(factoryMethodToUse);
                 }
             }
             // 如果工厂方法为空,则通过getCandidateMethods获取所有的待定方法
             if (candidateList == null) {
                 candidateList = new ArrayList<>();
                 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
                 for (Method candidate : rawCandidates) {
                     if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                         candidateList.add(candidate);
                     }
                 }
             }

             // 通过工厂方法创建bean
             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;
                 }
             }

             Method[] candidates = candidateList.toArray(new Method[0]);
             // 排序构造函数
             // public构造函数优先参数数量降序,非public构造函数参数数量降序
             AutowireUtils.sortFactoryMethods(candidates);

             // 用于承载解析后的构造函数参数的值
             ConstructorArgumentValues resolvedValues = null;
             boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
             int minTypeDiffWeight = Integer.MAX_VALUE;
             Set<Method> ambiguousFactoryMethods = null;

             int minNrOfArgs;
             if (explicitArgs != null) {
                 minNrOfArgs = explicitArgs.length;
             } 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.
                 // getBean没有传递参数,则需要解析保存在BeanDefinition构造函数中指定的参数
                 if (mbd.hasConstructorArgumentValues()) {
                     // 构造函数参数
                     ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                     resolvedValues = new ConstructorArgumentValues();
                     // 解析构造函数参数
                     // 将bean的构造函数解析为resolvedValues对象,其中会涉及到其他的bean
                     minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
                 } else {
                     minNrOfArgs = 0;
                 }
             }

             // 记录UnsatisfiedDependencyException异常集合
             LinkedList<UnsatisfiedDependencyException> causes = null;

             // 遍历candidates
             for (Method candidate : candidates) {
                 // 方法体参数
                 Class<?>[] paramTypes = candidate.getParameterTypes();

                 if (paramTypes.length >= minNrOfArgs) {
                     // 保存参数对象
                     ArgumentsHolder argsHolder;
                     // getBean()传递了参数
                     if (explicitArgs != null) {
                         // Explicit arguments given -> arguments length must match exactly.
                         // 显示给定参数,参数长度必须完全匹配
                         if (paramTypes.length != explicitArgs.length) {
                             continue;
                         }
                         // 根据参数创建参数持有者ArgumentsHolder对象
                         argsHolder = new ArgumentsHolder(explicitArgs);
                     } else {
                         // Resolved constructor arguments: type conversion and/or autowiring necessary.
                         // 根据提供的参数,解析构造函数
                         try {
                             String[] paramNames = null;
                             // 获取ParameterNameDiscoverer对象
                             // ParameterNameDiscoverer用于解析方法和构造函数的参数名,为参数名称探测器
                             ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                             // 获取指定构造函数的参数名
                             if (pnd != null) {
                                 paramNames = pnd.getParameterNames(candidate);
                             }
                             // 在已解析构造函数参数值的情况下,创建一个参数持有者ArgumentsHolder对象
                             argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                                              paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
                         } catch (UnsatisfiedDependencyException ex) {
                             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<>();
                             }
                             // 发生UnsatisfiedDependencyException异常,添加到causes中
                             causes.add(ex);
                             continue;
                         }
                     }

                     // isLenientConstructorResolution判断解析构造函数的时候是否以宽松模式还是严格模式
                     // 宽松模式:使用具有"最接近的模式"进行匹配
                     // 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
                     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);
                     }
                 }
             }

             // 没有可执行的工厂方法,则抛出异常
             if (factoryMethodToUse == null || argsToUse == 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);
             }

             // 将解析的构造函数加入缓存
             if (explicitArgs == null && argsHolderToUse != null) {
                 mbd.factoryMethodToIntrospect = factoryMethodToUse;
                 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
             }
         }

         // 创建bean对象,并设置到BeanWrapperImpl中
         bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
         return bw;
     }

分析:

由于该方法实在是太长了,因此对其进行分段分析。

#1 首先初始化了BeanwrapperImpl,需确认工厂对象,获取工厂名称,如果工厂名不为null,则走如下流程:

       String factoryBeanName = mbd.getFactoryBeanName();
         // 工厂名不为空
         if (factoryBeanName != null) {
             // 如果工厂名和beanName相等,则抛出BeanDefinitionStoreException异常
             if (factoryBeanName.equals(beanName)) {
                 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
                                                        "factory-bean reference points back to the same bean definition");
             }
             // 获取工厂实例
             factoryBean = this.beanFactory.getBean(factoryBeanName);
             // 如果是单例模式,并且已经缓存中已经存在beanName则抛出异常
             if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
                 throw new ImplicitlyAppearedSingletonException();
             }
             factoryClass = factoryBean.getClass();
             isStatic = false;
         } 

分析:

  • 如果factoryBeanName与beanName一样,则抛出BeanDefinitionStoreException异常。
  • 然后通过AbstractBeanFactory#getBean方法获取工厂实例对象。
  • 如果BeanDefinition为单例模式,且singletonObjects缓存中已经存在该bean对象了,则抛出异常。因为单例模式下且缓存中存在是不需要再次创建bean对象的,单例模式的bean只会实例化一次。

如果工厂名为null,则走如下分支:

      else {
             // 工厂名为空,则其可能是一个静态工厂
             // 静态工厂创建bean,必须要提供工厂的全类名
             // It's a static factory method on the bean 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;
         }

分析:

  • 如果BeanDefinition中没有解析类,则抛出异常,异常信息也描述得非常清晰:”bean definition的描述中既没有bean class也没有工厂的引用。
  • 将factoryClass设置为BeanDefinition的beanClass,并将isStatic=true,表明可能存在一个静态工厂。

#2 工厂对象确认后,需确认构造参数。

#2、1 如果explicitArgs存在,则直接使用该参数。explicitArgs是调用getBean方法的入参,如果该参数不为null,则可以确定构造函数的参数就是它了。

     // 确定构造参数
         // 如果getBean()已传递,则直接使用
         if (explicitArgs != null) {
             argsToUse = explicitArgs;
         }

#2、2 如果未传入构造参数,则走如下分支:

 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) {
                         argsToResolve = mbd.preparedConstructorArguments;
                     }
                 }
             }
             // 缓存中存在,则解析存储在BeanDefinition中的参数
             // 如给定方法的构造函数 f(int ,int),通过此方法后就会把配置文件中的("1","1")转换为(1,1)
             // 缓存中的值可能是原始值,也可能是最终值
             if (argsToResolve != null) {
                 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
             }
         }

分析:

整个流程其实就是尝试从缓存中获取构造函数参数,如果存在则通过resolvePreparedArguments进行转换,由于缓存中的值可能是最终值,也可能不是最终值。比如构造函数中的类型为Integer类型的1,但缓存中的类型有可能是String类型的”1″,所以即便是从缓存中得到了构造参数,也需要经过一番的类型转换才能确保参数类型完全对应。关于resolvePreparedArguments函数的解析,将在后续文章中体现。

#2、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.
             // 获取工厂方法的类的全类名
             factoryClass = ClassUtils.getUserClass(factoryClass);

             List<Method> candidateList = null;
             // 同步
             if (mbd.isFactoryMethodUnique) {
                 // 获取工厂方法
                 if (factoryMethodToUse == null) {
                     factoryMethodToUse = mbd.getResolvedFactoryMethod();
                 }
                 // 获取所有待定的工厂方法
                 if (factoryMethodToUse != null) {
                     candidateList = Collections.singletonList(factoryMethodToUse);
                 }
             }
             // 如果工厂方法为空,则通过getCandidateMethods获取所有的待定方法
             if (candidateList == null) {
                 candidateList = new ArrayList<>();
                 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
                 for (Method candidate : rawCandidates) {
                     if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
                         candidateList.add(candidate);
                     }
                 }
             }

             // 通过工厂方法创建bean
             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;
                 }
             }

分析:

如果在缓存中未到构造参数,则尝试通过native方法获取工厂方法类的全类名,如果得到工厂方法只有一个时,则通过instantiate方法实例化bean,然后注入到BeanWrapperImpl中,直接返回。

instantiate方法会在后面进行分析。

#2、4 当上述分支都不满足,则走如下分支:通过提取配置文件中的信息来执行构建操作(代码还是有些长,分段来看):

           Method[] candidates = candidateList.toArray(new Method[0]);
             // 排序构造函数
             // public构造函数优先参数数量降序,非public构造函数参数数量降序
             AutowireUtils.sortFactoryMethods(candidates);

             // 用于承载解析后的构造函数参数的值
             ConstructorArgumentValues resolvedValues = null;
             boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
             int minTypeDiffWeight = Integer.MAX_VALUE;
             Set<Method> ambiguousFactoryMethods = null;

             int minNrOfArgs;
             if (explicitArgs != null) {
                 minNrOfArgs = explicitArgs.length;
             } 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.
                 // getBean没有传递参数,则需要解析保存在BeanDefinition构造函数中指定的参数
                 if (mbd.hasConstructorArgumentValues()) {
                     // 构造函数参数
                     ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                     resolvedValues = new ConstructorArgumentValues();
                     // 解析构造函数参数
                     // 将bean的构造函数解析为resolvedValues对象,其中会涉及到其他的bean
                     minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
                 } else {
                     minNrOfArgs = 0;
                 }
             }

分析:

  • 首先对工厂方法进行排序处理,排序规则:public工厂方法优先,参数数量降序,然后非public工厂方法优先,参数数量降序。
  • 如果入参中带有构造参数,则直接获取构造参数的个数。
  • 否则需从BeanDefinition中获取构造函数,并进行解析。xml配置文件的构造函数解析在加载BeanDefinition的过程中有提及。
  • 然后通过resolveConstructorArguments解析构造函数,并返回构造参数的最小个数。resolveConstructorArguments函数目前这里不做分析。

#2、4.1 上步中确定了构造参数,接下来进行构造函数的确定:

           // 遍历candidates
             for (Method candidate : candidates) {
                 // 方法体参数
                 Class<?>[] paramTypes = candidate.getParameterTypes();

                 if (paramTypes.length >= minNrOfArgs) {
                     // 保存参数对象
                     ArgumentsHolder argsHolder;
                     // getBean()传递了参数
                     if (explicitArgs != null) {
                         // Explicit arguments given -> arguments length must match exactly.
                         // 显示给定参数,参数长度必须完全匹配
                         if (paramTypes.length != explicitArgs.length) {
                             continue;
                         }
                         // 根据参数创建参数持有者ArgumentsHolder对象
                         argsHolder = new ArgumentsHolder(explicitArgs);
                     } else {
                         // Resolved constructor arguments: type conversion and/or autowiring necessary.
                         // 根据提供的参数,解析构造函数
                         try {
                             String[] paramNames = null;
                             // 获取ParameterNameDiscoverer对象
                             // ParameterNameDiscoverer用于解析方法和构造函数的参数名,为参数名称探测器
                             ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                             // 获取指定构造函数的参数名
                             if (pnd != null) {
                                 paramNames = pnd.getParameterNames(candidate);
                             }
                             // 在已解析构造函数参数值的情况下,创建一个参数持有者ArgumentsHolder对象
                             argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
                                                              paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
                         } catch (UnsatisfiedDependencyException ex) {
                             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<>();
                             }
                             // 发生UnsatisfiedDependencyException异常,添加到causes中
                             causes.add(ex);
                             continue;
                         }
                     }

                     // isLenientConstructorResolution判断解析构造函数的时候是否以宽松模式还是严格模式
                     // 宽松模式:使用具有"最接近的模式"进行匹配
                     // 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
                     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);
                     }
                 }
             }

分析:

  • 遍历所有构造函数。
  • 如果方法体参数大于等于最小参数个数,则判断是否传入了构造参数,如果是,则根据入参创建参数持有者对象ArgumentsHolder;否则通过方法体获取指定构造函数的参数,并创建参数持有者对象ArgumentsHolder。
  • 接着确定构造函数的解析是使用宽松模式还是严格模式。
  • 严格模式:解析构造函数时,必须所有参数都需要匹配,否则抛出异常。
  • 宽松模式:使用具有”最接近的模式”进行匹配。

#3、在参数与工厂构造函数确认好后,就可以进行bean的实例化了

 // 没有可执行的工厂方法,则抛出异常
             if (factoryMethodToUse == null || argsToUse == 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);
             }

             // 将解析的构造函数加入缓存
             if (explicitArgs == null && argsHolderToUse != null) {
                 mbd.factoryMethodToIntrospect = factoryMethodToUse;
                 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
             }
         }

         // 创建bean对象,并设置到BeanWrapperImpl中
         bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
         return bw;

分析:

  • 如果工厂方法为空或构造参数为空,经过一系列异常判断后,最后会将解析的构造函数加入缓存。
  • 然后通过instantiate方法创建bean对象,并注入到BeanWrapperImpl中,最后返回bw。
 // ConstructorResolver

     public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
             synchronized (mbd.constructorArgumentLock) {
                 mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
                 mbd.constructorArgumentsResolved = true;
                 if (this.resolveNecessary) {
                     mbd.preparedConstructorArguments = this.preparedArguments;
                 } else {
                     mbd.resolvedConstructorArguments = this.arguments;
                 }
             }
         }

 // RootBeanDefinition.java
       /**
      * 构造函数的缓存锁
      * Common lock for the four constructor fields below.
      */
     final Object constructorArgumentLock = new Object();

     /**
      * 缓存已经解析的构造函数或工厂方法<br/>
      * Package-visible field for caching the resolved constructor or factory method.
      */
     @Nullable
     Executable resolvedConstructorOrFactoryMethod;

     /**
      * 标记字段:标记构造函数、参数是否已经解析,默认为false<br/>
      * Package-visible field that marks the constructor arguments as resolved.
      */
     boolean constructorArgumentsResolved = false;

     /**
      * 缓存已经解析的构造函数参数,包括可见字段<br/>
      * Package-visible field for caching fully resolved constructor arguments.
      */
     @Nullable
     Object[] resolvedConstructorArguments;

分析:

这里就是将构造函数、构造参数进行缓存,也就是最开始为什么要从缓存中获取的原因。

ConstructorResolver#instantiate

 private Object instantiate(String beanName, RootBeanDefinition mbd,
                                @Nullable Object factoryBean, Method factoryMethod, Object[] args) {

         try {

             if (System.getSecurityManager() != null) {
                 return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                                                              this.beanFactory.getInstantiationStrategy().instantiate(
                                                                      mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
                                                      this.beanFactory.getAccessControlContext());
             } else {
                 return this.beanFactory.getInstantiationStrategy().instantiate(
                         mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
             }
         } catch (Throwable ex) {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                             "Bean instantiation via factory method failed", ex);
         }
     }

分析:

该方法就是创建bean对象的方法,这里会委托调用SimpleInstantiationStrategy#instantiate方法。

 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
                               @Nullable Object factoryBean, final Method factoryMethod, Object... args) {

         try {
             // 设置method可访问
             if (System.getSecurityManager() != null) {
                 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                     ReflectionUtils.makeAccessible(factoryMethod);
                     return null;
                 });
             } else {
                 ReflectionUtils.makeAccessible(factoryMethod);
             }

             // 获得原method对象
             Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
             try {
                 // 设置新的method对象到currentlyInvokedFactoryMethod中
                 currentlyInvokedFactoryMethod.set(factoryMethod);
                 // 创建bean对象 通过反射执行工厂方法并返回创建的bean对象
                 Object result = factoryMethod.invoke(factoryBean, args);
                 // 未创建,则创建NullBean对象
                 if (result == null) {
                     result = new NullBean();
                 }
                 return result;
             } finally {
                 // 设置老的method对象到currentlyInvokedFactoryMethod中
                 if (priorInvokedFactoryMethod != null) {
                     currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
                 } else {
                     currentlyInvokedFactoryMethod.remove();
                 }
             }
         } catch (IllegalArgumentException ex) {
             throw new BeanInstantiationException(factoryMethod,
                                                  "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
                                                          "args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
         } catch (IllegalAccessException ex) {
             throw new BeanInstantiationException(factoryMethod,
                                                  "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
         } catch (InvocationTargetException ex) {
             String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
             if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
                     ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
                 msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
                         "declaring the factory method as static for independence from its containing instance. " + msg;
             }
             throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
         }
     }

分析:

  • 首先设置方法的可访问性。
  • 然后更新currentlyInvokedFactoryMethod缓存的方法。
  • 核心点是通过反射执行工厂方法创建bean对象。
  • 最后再次更新currentlyInvokedFactoryMethod。

至此通过工厂方法实例化Bean对象的过程分析完毕,真的是不容易,当然文中还有些方法未详细分析,后续再进行查漏补缺。

总结

instantiateUsingFactoryMethod方法体很大,但是其核心点就是确定工厂对象,获取构造函数和构造参数,最后通过SimpleInstantiationStrategy#instantiate反射执行工厂方法创建bean对象。


by Shawn Chen,2019.04.24日,下午。

出处:https://www.cnblogs.com/developer_chan/category/1347173.html

文章永久链接:https://tech.souyunku.com/13682

未经允许不得转载:搜云库技术团队 » 【spring源码分析】IOC容器初始化(九)

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们