zoukankan      html  css  js  c++  java
  • 【spring源码分析】IOC容器初始化(九)

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


    AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod

    1     protected BeanWrapper instantiateUsingFactoryMethod(
    2             String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
    3 
    4         return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
    5     }

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

      1 // ConstructorResolver
      2 public BeanWrapper instantiateUsingFactoryMethod(
      3             String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
      4         // 构造BeanWrapperImpl对象
      5         BeanWrapperImpl bw = new BeanWrapperImpl();
      6         // 初始化BeanWrapperImpl 向BeanWrapper对象中添加ConversionService对象和属性编辑器PropertyEditor对象
      7         this.beanFactory.initBeanWrapper(bw);
      8 
      9         // 获得factoryBean、factoryClass、isStatic、factoryBeanName属性
     10         Object factoryBean;
     11         Class<?> factoryClass;
     12         boolean isStatic;
     13 
     14         String factoryBeanName = mbd.getFactoryBeanName();
     15         // 工厂名不为空
     16         if (factoryBeanName != null) {
     17             // 如果工厂名和beanName相等,则抛出BeanDefinitionStoreException异常
     18             if (factoryBeanName.equals(beanName)) {
     19                 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
     20                                                        "factory-bean reference points back to the same bean definition");
     21             }
     22             // 获取工厂实例
     23             factoryBean = this.beanFactory.getBean(factoryBeanName);
     24             // 如果是单例模式,并且已经缓存中已经存在beanName则抛出异常
     25             if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
     26                 throw new ImplicitlyAppearedSingletonException();
     27             }
     28             factoryClass = factoryBean.getClass();
     29             isStatic = false;
     30         } else {
     31             // 工厂名为空,则其可能是一个静态工厂
     32             // 静态工厂创建bean,必须要提供工厂的全类名
     33             // It's a static factory method on the bean class.
     34             if (!mbd.hasBeanClass()) {
     35                 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
     36                                                        "bean definition declares neither a bean class nor a factory-bean reference");
     37             }
     38             factoryBean = null;
     39             factoryClass = mbd.getBeanClass();
     40             isStatic = true;
     41         }
     42 
     43         // 获得factoryMethodToUse、argsHolderToUse、argsToUse属性
     44         Method factoryMethodToUse = null;
     45         ArgumentsHolder argsHolderToUse = null;
     46         Object[] argsToUse = null;
     47 
     48         // 如果指定了构造参数则直接使用
     49         // 在调用getBean方法的时候指定方法参数
     50         if (explicitArgs != null) {
     51             argsToUse = explicitArgs;
     52         } else {
     53             // 没有指定,则尝试从配置文件中解析
     54             Object[] argsToResolve = null;
     55             // 同步
     56             synchronized (mbd.constructorArgumentLock) {
     57                 // 获取缓存中的构造函数或者工厂方法
     58                 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
     59                 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
     60                     // 获取缓存中的构造参数
     61                     // Found a cached factory method...
     62                     argsToUse = mbd.resolvedConstructorArguments;
     63                     if (argsToUse == null) {
     64                         argsToResolve = mbd.preparedConstructorArguments;
     65                     }
     66                 }
     67             }
     68             // 缓存中存在,则解析存储在BeanDefinition中的参数
     69             // 如给定方法的构造函数 f(int ,int),通过此方法后就会把配置文件中的("1","1")转换为(1,1)
     70             // 缓存中的值可能是原始值,也可能是最终值
     71             if (argsToResolve != null) {
     72                 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
     73             }
     74         }
     75 
     76         if (factoryMethodToUse == null || argsToUse == null) {
     77             // Need to determine the factory method...
     78             // Try all methods with this name to see if they match the given arguments.
     79             // 获取工厂方法的类的全类名
     80             factoryClass = ClassUtils.getUserClass(factoryClass);
     81 
     82             List<Method> candidateList = null;
     83             // 同步
     84             if (mbd.isFactoryMethodUnique) {
     85                 // 获取工厂方法
     86                 if (factoryMethodToUse == null) {
     87                     factoryMethodToUse = mbd.getResolvedFactoryMethod();
     88                 }
     89                 // 获取所有待定的工厂方法
     90                 if (factoryMethodToUse != null) {
     91                     candidateList = Collections.singletonList(factoryMethodToUse);
     92                 }
     93             }
     94             // 如果工厂方法为空,则通过getCandidateMethods获取所有的待定方法
     95             if (candidateList == null) {
     96                 candidateList = new ArrayList<>();
     97                 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
     98                 for (Method candidate : rawCandidates) {
     99                     if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
    100                         candidateList.add(candidate);
    101                     }
    102                 }
    103             }
    104 
    105             // 通过工厂方法创建bean
    106             if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
    107                 Method uniqueCandidate = candidateList.get(0);
    108                 if (uniqueCandidate.getParameterCount() == 0) {
    109                     mbd.factoryMethodToIntrospect = uniqueCandidate;
    110                     synchronized (mbd.constructorArgumentLock) {
    111                         mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
    112                         mbd.constructorArgumentsResolved = true;
    113                         mbd.resolvedConstructorArguments = EMPTY_ARGS;
    114                     }
    115                     bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
    116                     return bw;
    117                 }
    118             }
    119 
    120             Method[] candidates = candidateList.toArray(new Method[0]);
    121             // 排序构造函数
    122             // public构造函数优先参数数量降序,非public构造函数参数数量降序
    123             AutowireUtils.sortFactoryMethods(candidates);
    124 
    125             // 用于承载解析后的构造函数参数的值
    126             ConstructorArgumentValues resolvedValues = null;
    127             boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
    128             int minTypeDiffWeight = Integer.MAX_VALUE;
    129             Set<Method> ambiguousFactoryMethods = null;
    130 
    131             int minNrOfArgs;
    132             if (explicitArgs != null) {
    133                 minNrOfArgs = explicitArgs.length;
    134             } else {
    135                 // We don't have arguments passed in programmatically, so we need to resolve the
    136                 // arguments specified in the constructor arguments held in the bean definition.
    137                 // getBean没有传递参数,则需要解析保存在BeanDefinition构造函数中指定的参数
    138                 if (mbd.hasConstructorArgumentValues()) {
    139                     // 构造函数参数
    140                     ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
    141                     resolvedValues = new ConstructorArgumentValues();
    142                     // 解析构造函数参数
    143                     // 将bean的构造函数解析为resolvedValues对象,其中会涉及到其他的bean
    144                     minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
    145                 } else {
    146                     minNrOfArgs = 0;
    147                 }
    148             }
    149 
    150             // 记录UnsatisfiedDependencyException异常集合
    151             LinkedList<UnsatisfiedDependencyException> causes = null;
    152 
    153             // 遍历candidates
    154             for (Method candidate : candidates) {
    155                 // 方法体参数
    156                 Class<?>[] paramTypes = candidate.getParameterTypes();
    157 
    158                 if (paramTypes.length >= minNrOfArgs) {
    159                     // 保存参数对象
    160                     ArgumentsHolder argsHolder;
    161                     // getBean()传递了参数
    162                     if (explicitArgs != null) {
    163                         // Explicit arguments given -> arguments length must match exactly.
    164                         // 显示给定参数,参数长度必须完全匹配
    165                         if (paramTypes.length != explicitArgs.length) {
    166                             continue;
    167                         }
    168                         // 根据参数创建参数持有者ArgumentsHolder对象
    169                         argsHolder = new ArgumentsHolder(explicitArgs);
    170                     } else {
    171                         // Resolved constructor arguments: type conversion and/or autowiring necessary.
    172                         // 根据提供的参数,解析构造函数
    173                         try {
    174                             String[] paramNames = null;
    175                             // 获取ParameterNameDiscoverer对象
    176                             // ParameterNameDiscoverer用于解析方法和构造函数的参数名,为参数名称探测器
    177                             ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
    178                             // 获取指定构造函数的参数名
    179                             if (pnd != null) {
    180                                 paramNames = pnd.getParameterNames(candidate);
    181                             }
    182                             // 在已解析构造函数参数值的情况下,创建一个参数持有者ArgumentsHolder对象
    183                             argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
    184                                                              paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
    185                         } catch (UnsatisfiedDependencyException ex) {
    186                             if (logger.isTraceEnabled()) {
    187                                 logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
    188                             }
    189                             // Swallow and try next overloaded factory method.
    190                             if (causes == null) {
    191                                 causes = new LinkedList<>();
    192                             }
    193                             // 发生UnsatisfiedDependencyException异常,添加到causes中
    194                             causes.add(ex);
    195                             continue;
    196                         }
    197                     }
    198 
    199                     // isLenientConstructorResolution判断解析构造函数的时候是否以宽松模式还是严格模式
    200                     // 宽松模式:使用具有"最接近的模式"进行匹配
    201                     // 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
    202                     int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
    203                             argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
    204                     // Choose this factory method if it represents the closest match.
    205                     // 代表最接近的类型匹配,选择作为构造函数
    206                     if (typeDiffWeight < minTypeDiffWeight) {
    207                         factoryMethodToUse = candidate;
    208                         argsHolderToUse = argsHolder;
    209                         argsToUse = argsHolder.arguments;
    210                         minTypeDiffWeight = typeDiffWeight;
    211                         ambiguousFactoryMethods = null;
    212                     }
    213                     // Find out about ambiguity: In case of the same type difference weight
    214                     // for methods with the same number of parameters, collect such candidates
    215                     // and eventually raise an ambiguity exception.
    216                     // However, only perform that check in non-lenient constructor resolution mode,
    217                     // and explicitly ignore overridden methods (with the same parameter signature).
    218                     // 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项
    219                     // 但是仅在非宽松模式构造函数解析模式下执行该检查,并显示忽略重写方法(具有相同的参数签名)
    220                     else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
    221                             !mbd.isLenientConstructorResolution() &&
    222                             paramTypes.length == factoryMethodToUse.getParameterCount() &&
    223                             !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
    224                         // 查找多个可匹配的方法
    225                         if (ambiguousFactoryMethods == null) {
    226                             ambiguousFactoryMethods = new LinkedHashSet<>();
    227                             ambiguousFactoryMethods.add(factoryMethodToUse);
    228                         }
    229                         ambiguousFactoryMethods.add(candidate);
    230                     }
    231                 }
    232             }
    233 
    234             // 没有可执行的工厂方法,则抛出异常
    235             if (factoryMethodToUse == null || argsToUse == null) {
    236                 if (causes != null) {
    237                     UnsatisfiedDependencyException ex = causes.removeLast();
    238                     for (Exception cause : causes) {
    239                         this.beanFactory.onSuppressedException(cause);
    240                     }
    241                     throw ex;
    242                 }
    243                 List<String> argTypes = new ArrayList<>(minNrOfArgs);
    244                 if (explicitArgs != null) {
    245                     for (Object arg : explicitArgs) {
    246                         argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
    247                     }
    248                 } else if (resolvedValues != null) {
    249                     Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
    250                     valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
    251                     valueHolders.addAll(resolvedValues.getGenericArgumentValues());
    252                     for (ValueHolder value : valueHolders) {
    253                         String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
    254                                 (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
    255                         argTypes.add(argType);
    256                     }
    257                 }
    258                 String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
    259                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    260                                                 "No matching factory method found: " +
    261                                                         (mbd.getFactoryBeanName() != null ?
    262                                                                 "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
    263                                                         "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
    264                                                         "Check that a method with the specified name " +
    265                                                         (minNrOfArgs > 0 ? "and arguments " : "") +
    266                                                         "exists and that it is " +
    267                                                         (isStatic ? "static" : "non-static") + ".");
    268             } else if (void.class == factoryMethodToUse.getReturnType()) {
    269                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    270                                                 "Invalid factory method '" + mbd.getFactoryMethodName() +
    271                                                         "': needs to have a non-void return type!");
    272             } else if (ambiguousFactoryMethods != null) {
    273                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    274                                                 "Ambiguous factory method matches found in bean '" + beanName + "' " +
    275                                                         "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
    276                                                         ambiguousFactoryMethods);
    277             }
    278 
    279             // 将解析的构造函数加入缓存
    280             if (explicitArgs == null && argsHolderToUse != null) {
    281                 mbd.factoryMethodToIntrospect = factoryMethodToUse;
    282                 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
    283             }
    284         }
    285 
    286         // 创建bean对象,并设置到BeanWrapperImpl中
    287         bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
    288         return bw;
    289     }

    分析:

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

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

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

    分析:

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

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

     1      else {
     2             // 工厂名为空,则其可能是一个静态工厂
     3             // 静态工厂创建bean,必须要提供工厂的全类名
     4             // It's a static factory method on the bean class.
     5             if (!mbd.hasBeanClass()) {
     6                 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
     7                                                        "bean definition declares neither a bean class nor a factory-bean reference");
     8             }
     9             factoryBean = null;
    10             factoryClass = mbd.getBeanClass();
    11             isStatic = true;
    12         }

    分析:

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

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

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

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

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

     1 else {
     2             // 没有指定,则尝试从缓存中获取
     3             Object[] argsToResolve = null;
     4             // 同步
     5             synchronized (mbd.constructorArgumentLock) {
     6                 // 获取缓存中的构造函数或者工厂方法
     7                 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
     8                 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
     9                     // 获取缓存中的构造参数
    10                     // Found a cached factory method...
    11                     argsToUse = mbd.resolvedConstructorArguments;
    12                     if (argsToUse == null) {
    13                         argsToResolve = mbd.preparedConstructorArguments;
    14                     }
    15                 }
    16             }
    17             // 缓存中存在,则解析存储在BeanDefinition中的参数
    18             // 如给定方法的构造函数 f(int ,int),通过此方法后就会把配置文件中的("1","1")转换为(1,1)
    19             // 缓存中的值可能是原始值,也可能是最终值
    20             if (argsToResolve != null) {
    21                 argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
    22             }
    23         }

    分析:

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

    #2.3 如果缓存中未获取到构造参数,则走如下分支:

     1 if (factoryMethodToUse == null || argsToUse == null) {
     2             // Need to determine the factory method...
     3             // Try all methods with this name to see if they match the given arguments.
     4             // 获取工厂方法的类的全类名
     5             factoryClass = ClassUtils.getUserClass(factoryClass);
     6 
     7             List<Method> candidateList = null;
     8             // 同步
     9             if (mbd.isFactoryMethodUnique) {
    10                 // 获取工厂方法
    11                 if (factoryMethodToUse == null) {
    12                     factoryMethodToUse = mbd.getResolvedFactoryMethod();
    13                 }
    14                 // 获取所有待定的工厂方法
    15                 if (factoryMethodToUse != null) {
    16                     candidateList = Collections.singletonList(factoryMethodToUse);
    17                 }
    18             }
    19             // 如果工厂方法为空,则通过getCandidateMethods获取所有的待定方法
    20             if (candidateList == null) {
    21                 candidateList = new ArrayList<>();
    22                 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
    23                 for (Method candidate : rawCandidates) {
    24                     if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
    25                         candidateList.add(candidate);
    26                     }
    27                 }
    28             }
    29 
    30             // 通过工厂方法创建bean
    31             if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
    32                 Method uniqueCandidate = candidateList.get(0);
    33                 if (uniqueCandidate.getParameterCount() == 0) {
    34                     mbd.factoryMethodToIntrospect = uniqueCandidate;
    35                     synchronized (mbd.constructorArgumentLock) {
    36                         mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
    37                         mbd.constructorArgumentsResolved = true;
    38                         mbd.resolvedConstructorArguments = EMPTY_ARGS;
    39                     }
    40                     bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
    41                     return bw;
    42                 }
    43             }

    分析:

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

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

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

     1           Method[] candidates = candidateList.toArray(new Method[0]);
     2             // 排序构造函数
     3             // public构造函数优先参数数量降序,非public构造函数参数数量降序
     4             AutowireUtils.sortFactoryMethods(candidates);
     5 
     6             // 用于承载解析后的构造函数参数的值
     7             ConstructorArgumentValues resolvedValues = null;
     8             boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
     9             int minTypeDiffWeight = Integer.MAX_VALUE;
    10             Set<Method> ambiguousFactoryMethods = null;
    11 
    12             int minNrOfArgs;
    13             if (explicitArgs != null) {
    14                 minNrOfArgs = explicitArgs.length;
    15             } else {
    16                 // We don't have arguments passed in programmatically, so we need to resolve the
    17                 // arguments specified in the constructor arguments held in the bean definition.
    18                 // getBean没有传递参数,则需要解析保存在BeanDefinition构造函数中指定的参数
    19                 if (mbd.hasConstructorArgumentValues()) {
    20                     // 构造函数参数
    21                     ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
    22                     resolvedValues = new ConstructorArgumentValues();
    23                     // 解析构造函数参数
    24                     // 将bean的构造函数解析为resolvedValues对象,其中会涉及到其他的bean
    25                     minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
    26                 } else {
    27                     minNrOfArgs = 0;
    28                 }
    29             }

    分析:

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

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

     1           // 遍历candidates
     2             for (Method candidate : candidates) {
     3                 // 方法体参数
     4                 Class<?>[] paramTypes = candidate.getParameterTypes();
     5 
     6                 if (paramTypes.length >= minNrOfArgs) {
     7                     // 保存参数对象
     8                     ArgumentsHolder argsHolder;
     9                     // getBean()传递了参数
    10                     if (explicitArgs != null) {
    11                         // Explicit arguments given -> arguments length must match exactly.
    12                         // 显示给定参数,参数长度必须完全匹配
    13                         if (paramTypes.length != explicitArgs.length) {
    14                             continue;
    15                         }
    16                         // 根据参数创建参数持有者ArgumentsHolder对象
    17                         argsHolder = new ArgumentsHolder(explicitArgs);
    18                     } else {
    19                         // Resolved constructor arguments: type conversion and/or autowiring necessary.
    20                         // 根据提供的参数,解析构造函数
    21                         try {
    22                             String[] paramNames = null;
    23                             // 获取ParameterNameDiscoverer对象
    24                             // ParameterNameDiscoverer用于解析方法和构造函数的参数名,为参数名称探测器
    25                             ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
    26                             // 获取指定构造函数的参数名
    27                             if (pnd != null) {
    28                                 paramNames = pnd.getParameterNames(candidate);
    29                             }
    30                             // 在已解析构造函数参数值的情况下,创建一个参数持有者ArgumentsHolder对象
    31                             argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
    32                                                              paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
    33                         } catch (UnsatisfiedDependencyException ex) {
    34                             if (logger.isTraceEnabled()) {
    35                                 logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
    36                             }
    37                             // Swallow and try next overloaded factory method.
    38                             if (causes == null) {
    39                                 causes = new LinkedList<>();
    40                             }
    41                             // 发生UnsatisfiedDependencyException异常,添加到causes中
    42                             causes.add(ex);
    43                             continue;
    44                         }
    45                     }
    46 
    47                     // isLenientConstructorResolution判断解析构造函数的时候是否以宽松模式还是严格模式
    48                     // 宽松模式:使用具有"最接近的模式"进行匹配
    49                     // 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
    50                     int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
    51                             argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
    52                     // Choose this factory method if it represents the closest match.
    53                     // 代表最接近的类型匹配,选择作为构造函数
    54                     if (typeDiffWeight < minTypeDiffWeight) {
    55                         factoryMethodToUse = candidate;
    56                         argsHolderToUse = argsHolder;
    57                         argsToUse = argsHolder.arguments;
    58                         minTypeDiffWeight = typeDiffWeight;
    59                         ambiguousFactoryMethods = null;
    60                     }
    61                     // Find out about ambiguity: In case of the same type difference weight
    62                     // for methods with the same number of parameters, collect such candidates
    63                     // and eventually raise an ambiguity exception.
    64                     // However, only perform that check in non-lenient constructor resolution mode,
    65                     // and explicitly ignore overridden methods (with the same parameter signature).
    66                     // 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项
    67                     // 但是仅在非宽松模式构造函数解析模式下执行该检查,并显示忽略重写方法(具有相同的参数签名)
    68                     else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
    69                             !mbd.isLenientConstructorResolution() &&
    70                             paramTypes.length == factoryMethodToUse.getParameterCount() &&
    71                             !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
    72                         // 查找多个可匹配的方法
    73                         if (ambiguousFactoryMethods == null) {
    74                             ambiguousFactoryMethods = new LinkedHashSet<>();
    75                             ambiguousFactoryMethods.add(factoryMethodToUse);
    76                         }
    77                         ambiguousFactoryMethods.add(candidate);
    78                     }
    79                 }
    80             }

    分析: 

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

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

     1 // 没有可执行的工厂方法,则抛出异常
     2             if (factoryMethodToUse == null || argsToUse == null) {
     3                 if (causes != null) {
     4                     UnsatisfiedDependencyException ex = causes.removeLast();
     5                     for (Exception cause : causes) {
     6                         this.beanFactory.onSuppressedException(cause);
     7                     }
     8                     throw ex;
     9                 }
    10                 List<String> argTypes = new ArrayList<>(minNrOfArgs);
    11                 if (explicitArgs != null) {
    12                     for (Object arg : explicitArgs) {
    13                         argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
    14                     }
    15                 } else if (resolvedValues != null) {
    16                     Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
    17                     valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
    18                     valueHolders.addAll(resolvedValues.getGenericArgumentValues());
    19                     for (ValueHolder value : valueHolders) {
    20                         String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
    21                                 (value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
    22                         argTypes.add(argType);
    23                     }
    24                 }
    25                 String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
    26                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    27                                                 "No matching factory method found: " +
    28                                                         (mbd.getFactoryBeanName() != null ?
    29                                                                 "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
    30                                                         "factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
    31                                                         "Check that a method with the specified name " +
    32                                                         (minNrOfArgs > 0 ? "and arguments " : "") +
    33                                                         "exists and that it is " +
    34                                                         (isStatic ? "static" : "non-static") + ".");
    35             } else if (void.class == factoryMethodToUse.getReturnType()) {
    36                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    37                                                 "Invalid factory method '" + mbd.getFactoryMethodName() +
    38                                                         "': needs to have a non-void return type!");
    39             } else if (ambiguousFactoryMethods != null) {
    40                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    41                                                 "Ambiguous factory method matches found in bean '" + beanName + "' " +
    42                                                         "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
    43                                                         ambiguousFactoryMethods);
    44             }
    45 
    46             // 将解析的构造函数加入缓存
    47             if (explicitArgs == null && argsHolderToUse != null) {
    48                 mbd.factoryMethodToIntrospect = factoryMethodToUse;
    49                 argsHolderToUse.storeCache(mbd, factoryMethodToUse);
    50             }
    51         }
    52 
    53         // 创建bean对象,并设置到BeanWrapperImpl中
    54         bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
    55         return bw;

    分析:

    • 如果工厂方法为空或构造参数为空,经过一系列异常判断后,最后会将解析的构造函数加入缓存。
    • 然后通过instantiate方法创建bean对象,并注入到BeanWrapperImpl中,最后返回bw。
     1 // ConstructorResolver
     2 
     3     public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
     4             synchronized (mbd.constructorArgumentLock) {
     5                 mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
     6                 mbd.constructorArgumentsResolved = true;
     7                 if (this.resolveNecessary) {
     8                     mbd.preparedConstructorArguments = this.preparedArguments;
     9                 } else {
    10                     mbd.resolvedConstructorArguments = this.arguments;
    11                 }
    12             }
    13         }
    14 
    15 // RootBeanDefinition.java
    16       /**
    17      * 构造函数的缓存锁
    18      * Common lock for the four constructor fields below.
    19      */
    20     final Object constructorArgumentLock = new Object();
    21 
    22     /**
    23      * 缓存已经解析的构造函数或工厂方法<br/>
    24      * Package-visible field for caching the resolved constructor or factory method.
    25      */
    26     @Nullable
    27     Executable resolvedConstructorOrFactoryMethod;
    28 
    29     /**
    30      * 标记字段:标记构造函数、参数是否已经解析,默认为false<br/>
    31      * Package-visible field that marks the constructor arguments as resolved.
    32      */
    33     boolean constructorArgumentsResolved = false;
    34 
    35     /**
    36      * 缓存已经解析的构造函数参数,包括可见字段<br/>
    37      * Package-visible field for caching fully resolved constructor arguments.
    38      */
    39     @Nullable
    40     Object[] resolvedConstructorArguments;

    分析:

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

    ConstructorResolver#instantiate

     1 private Object instantiate(String beanName, RootBeanDefinition mbd,
     2                                @Nullable Object factoryBean, Method factoryMethod, Object[] args) {
     3 
     4         try {
     5 
     6             if (System.getSecurityManager() != null) {
     7                 return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
     8                                                              this.beanFactory.getInstantiationStrategy().instantiate(
     9                                                                      mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
    10                                                      this.beanFactory.getAccessControlContext());
    11             } else {
    12                 return this.beanFactory.getInstantiationStrategy().instantiate(
    13                         mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
    14             }
    15         } catch (Throwable ex) {
    16             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    17                                             "Bean instantiation via factory method failed", ex);
    18         }
    19     }

    分析:

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

     1 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
     2                               @Nullable Object factoryBean, final Method factoryMethod, Object... args) {
     3 
     4         try {
     5             // 设置method可访问
     6             if (System.getSecurityManager() != null) {
     7                 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
     8                     ReflectionUtils.makeAccessible(factoryMethod);
     9                     return null;
    10                 });
    11             } else {
    12                 ReflectionUtils.makeAccessible(factoryMethod);
    13             }
    14 
    15             // 获得原method对象
    16             Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
    17             try {
    18                 // 设置新的method对象到currentlyInvokedFactoryMethod中
    19                 currentlyInvokedFactoryMethod.set(factoryMethod);
    20                 // 创建bean对象 通过反射执行工厂方法并返回创建的bean对象
    21                 Object result = factoryMethod.invoke(factoryBean, args);
    22                 // 未创建,则创建NullBean对象
    23                 if (result == null) {
    24                     result = new NullBean();
    25                 }
    26                 return result;
    27             } finally {
    28                 // 设置老的method对象到currentlyInvokedFactoryMethod中
    29                 if (priorInvokedFactoryMethod != null) {
    30                     currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
    31                 } else {
    32                     currentlyInvokedFactoryMethod.remove();
    33                 }
    34             }
    35         } catch (IllegalArgumentException ex) {
    36             throw new BeanInstantiationException(factoryMethod,
    37                                                  "Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
    38                                                          "args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
    39         } catch (IllegalAccessException ex) {
    40             throw new BeanInstantiationException(factoryMethod,
    41                                                  "Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
    42         } catch (InvocationTargetException ex) {
    43             String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
    44             if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
    45                     ((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
    46                 msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
    47                         "declaring the factory method as static for independence from its containing instance. " + msg;
    48             }
    49             throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
    50         }
    51     }

    分析:

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

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

    总结

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


    by Shawn Chen,2019.04.24日,下午。

  • 相关阅读:
    【zZ】OpenCV HOGDescriptor 参数图解
    [C]遍历目录下所有文件
    drawing
    转:基于用户投票的排名算法系列
    编码格式
    泛型
    接口
    隐藏方法不能实现多态性
    结构
    静态
  • 原文地址:https://www.cnblogs.com/developer_chan/p/10758926.html
Copyright © 2011-2022 走看看