Spring - 推断构造方法【2】

310 阅读6分钟

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

【1】autowireConstructor

protected BeanWrapper autowireConstructor(

      String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {

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

前面的就只是一个构造方法,重要的是下面的:

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
   //ctors:从这些方法中取一个来
    //args:getBean中,手动传的参数
      @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

   BeanWrapperImpl bw = new BeanWrapperImpl();
   this.beanFactory.initBeanWrapper(bw);

    //最终选的构造方法和对应的参数
   Constructor<?> constructorToUse = null;
   ArgumentsHolder argsHolderToUse = null;
   Object[] argsToUse = null;

   if (explicitArgs != null) {
       //如果args指定了,那么直接用这些指定的参数来构造
      argsToUse = explicitArgs;
   }
   else {
      Object[] argsToResolve = null;
       //构造方法有没有缓存
      synchronized (mbd.constructorArgumentLock) {
         constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
          //有缓存
         if (constructorToUse != null && mbd.constructorArgumentsResolved) {
            // Found a cached constructor...
            argsToUse = mbd.resolvedConstructorArguments;
            if (argsToUse == null) {
                //和RuntimeBeanReference有关,这里在后面回去解析[T(1)]
               argsToResolve = mbd.preparedConstructorArguments;
            }
         }
      }
      if (argsToResolve != null) {
         //上面[T(1)]的地方就会在这里来解析
         argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
      }
   }

    //两个至少有一个未知,也就是说:此时还没有办法来构造类示例
   if (constructorToUse == null || argsToUse == null) {
      Constructor<?>[] candidates = chosenCtors;
       //如果之前没有给到构造方法
      if (candidates == null) {
         Class<?> beanClass = mbd.getBeanClass();
         try {
             //根据bd的配置,来决定取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);
         }
      }

       //如果只有一个构造方法可以选用,且没有手动指定参数,且BD里也没有传值
      if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
          //是否构造方法是无参的?
         Constructor<?> uniqueCandidate = candidates[0];
          //是无参的,就直接构建了
         if (uniqueCandidate.getParameterCount() == 0) {
            synchronized (mbd.constructorArgumentLock) {
               mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
               mbd.constructorArgumentsResolved = true;
               mbd.resolvedConstructorArguments = EMPTY_ARGS;
            }
            bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
            return bw;
         }
      }

      //有若干个构造方法,往下需要从这里面选1个来构造示例
      boolean autowiring = (chosenCtors != null ||
            mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
      ConstructorArgumentValues resolvedValues = null;

       //这个变量,指的是参数个数如果比这个数少,那么就不会用来构造示例
      int minNrOfArgs;
       //这里的参数就是前面手动getBean时传进来的
      if (explicitArgs != null) {
         minNrOfArgs = explicitArgs.length;
      }
      else {
          //这里指的是通过BD,来手动指定的参数的个数
         ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
         resolvedValues = new ConstructorArgumentValues();
         minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
      }

       //这里会排序,排序规则是:优先public,随后参数个数倒序
      AutowireUtils.sortConstructors(candidates);
       //这个参数,指的是构造方法的得分:因为即使我们确定了某个构造方法,但可能参数个数是一样的,我们需要根据某些方式,去确认具体选择哪一个
      int minTypeDiffWeight = Integer.MAX_VALUE;
      Set<Constructor<?>> ambiguousConstructors = null;
      Deque<UnsatisfiedDependencyException> causes = null;

       //遍历上面排序的构造方法
      for (Constructor<?> candidate : candidates) {
         int parameterCount = candidate.getParameterCount();

          //这里已经选了某个构造方法,然后当前的构造方法,参数个数小于minNrOfArgs,那么就没必要再查看了,直接返回
         if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
            // Already found greedy constructor that can be satisfied ->
            // do not look any further, there are only less greedy constructors left.
            break;
         }
           //这里还没选选某个构造方法,参数个数小于minNrOfArgs:此时要考虑private的构造方法,因此需要继续
         if (parameterCount < minNrOfArgs) {
            continue;
         }
		
         ArgumentsHolder argsHolder;
         Class<?>[] paramTypes = candidate.getParameterTypes();
         if (resolvedValues != null) {
            try {
                //取参数名称【1.1】
               String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
               if (paramNames == null) {
                   //获取代码中参数的名称
                  ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                  if (pnd != null) {
                     paramNames = pnd.getParameterNames(candidate);
                  }
               }
                //这里就是根据参数类型、名称,找对应的bean对象【1.2】
               argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                     getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
            }
            catch (UnsatisfiedDependencyException ex) {
               if (logger.isTraceEnabled()) {
                  logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
               }
               // Swallow and try next constructor.
               if (causes == null) {
                  causes = new ArrayDeque<>(1);
               }
               causes.add(ex);
               continue;
            }
         }
         else {
            // Explicit arguments given -> arguments length must match exactly.
            if (parameterCount != explicitArgs.length) {
               continue;
            }
            argsHolder = new ArgumentsHolder(explicitArgs);
         }
		//看,这里就会来计算得分,来确认构造方法【1.3】
         int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
               argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
         // Choose this constructor if it represents the closest match.
          //看,这里就会来计算得分
          //规则是:等分不变更,小分才会变更,这意味着同分下先被找到的有更高的执行可能
         if (typeDiffWeight < minTypeDiffWeight) {
            constructorToUse = candidate;
            argsHolderToUse = argsHolder;
            argsToUse = argsHolder.arguments;
            minTypeDiffWeight = typeDiffWeight;
            ambiguousConstructors = null;
         }
          //如果得分相等,那么需要记录一下冲突的情况,如果最后还存在这个过程,那么就会抛出异常
         else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
            if (ambiguousConstructors == null) {
               ambiguousConstructors = new LinkedHashSet<>();
               ambiguousConstructors.add(constructorToUse);
            }
            ambiguousConstructors.add(candidate);
         }
      }
		//这里指的就是:最终没有找到合适的构造方法
       //为什么?可能是某个参数找bean并没有找到(例如:根据类找找到多个,然后根据名字找,但名字找不到),在前面会存起来
      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 on bean class [" + mbd.getBeanClassName() + "] " +
               "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
      }
       //有多个分数相同的构造方法,且mbd不是宽松模式,那么就会报错
      else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Ambiguous constructor matches found on bean class [" + mbd.getBeanClassName() + "] " +
               "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
               ambiguousConstructors);
      }
		//到这里就会根据之前的构造方法,来存缓存
      if (explicitArgs == null && argsHolderToUse != null) {
         argsHolderToUse.storeCache(mbd, constructorToUse);
      }
   }
//这里就会构造bean示例
   Assert.state(argsToUse != null, "Unresolved constructor arguments");
   bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
   return bw;
}

【1.1】构造方法@ConstructorProperties

可以在构造方法上,通过该注解来指定参数别名:

@ConstructorProperties({"1","2","3",...})

【1.2】 createArgumentArray

private ArgumentsHolder createArgumentArray(
      String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
      BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
      boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {

   TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
   TypeConverter converter = (customConverter != null ? customConverter : bw);

   ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
   Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
   Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//遍历构造方法的参数类型
   for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
       //看参数类型和名称
      Class<?> paramType = paramTypes[paramIndex];
      String paramName = (paramNames != null ? paramNames[paramIndex] : "");
      // Try to find matching constructor argument value, either indexed or generic.
      ConstructorArgumentValues.ValueHolder valueHolder = null;
      if (resolvedValues != null) {
         valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
         // If we couldn't find a direct match and are not supposed to autowire,
         // let's try the next generic, untyped argument value as fallback:
         // it could match after type conversion (for example, String -> int).
         if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
            valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
         }
      }
      if (valueHolder != null) {
         // We found a potential match - let's give it a try.
         // Do not consider the same value definition multiple times!
         usedValueHolders.add(valueHolder);
         Object originalValue = valueHolder.getValue();
         Object convertedValue;
         if (valueHolder.isConverted()) {
            convertedValue = valueHolder.getConvertedValue();
            args.preparedArguments[paramIndex] = convertedValue;
         }
         else {
            MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
            try {
               convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
            }
            catch (TypeMismatchException ex) {
               throw new UnsatisfiedDependencyException(
                     mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
                     "Could not convert argument value of type [" +
                           ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
                           "] to required type [" + paramType.getName() + "]: " + ex.getMessage());
            }
            Object sourceHolder = valueHolder.getSource();
            if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
               Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
               args.resolveNecessary = true;
               args.preparedArguments[paramIndex] = sourceValue;
            }
         }
         args.arguments[paramIndex] = convertedValue;
         args.rawArguments[paramIndex] = originalValue;
      }
      else {
         MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
         // No explicit match found: we're either supposed to autowire or
         // have to fail creating an argument array for the given constructor.
         if (!autowiring) {
            throw new UnsatisfiedDependencyException(
                  mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
                  "Ambiguous argument values for parameter of type [" + paramType.getName() +
                  "] - did you specify the correct bean references as arguments?");
         }
         try {
             //如果某个参数没指定,且autowired为true
            //这里会调用依赖注入里面的resolveDependency方法:根据类型再名字,来从容器里找bean对象尝试赋值
            Object autowiredArgument = resolveAutowiredArgument(
                  methodParam, beanName, autowiredBeanNames, converter, fallback);
             //存起来,给外面构造方法来使用 
            args.rawArguments[paramIndex] = autowiredArgument;
            args.arguments[paramIndex] = autowiredArgument;
            args.preparedArguments[paramIndex] = autowiredArgumentMarker;
            args.resolveNecessary = true;
         }
         catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(
                  mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
         }
      }
   }

   for (String autowiredBeanName : autowiredBeanNames) {
      this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
      if (logger.isDebugEnabled()) {
         logger.debug("Autowiring by type from bean name '" + beanName +
               "' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
               " to bean named '" + autowiredBeanName + "'");
      }
   }

   return args;
}

【1.3】分数计算

int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
      argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));

可以看到这里还是分为宽松模式和非宽松模式的:

宽松模式:

public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
   // If valid arguments found, determine type difference weight.
   // Try type difference weight on both the converted arguments and
   // the raw arguments. If the raw weight is better, use it.
   // Decrease raw weight by 1024 to prefer it over equal converted weight.
    //这里:arguments代表找到并转换后的arguments;rawArguments指:找到的arguments
   int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);
   int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
   return Math.min(rawTypeDiffWeight, typeDiffWeight);
}

而计算的在这里:

public static int getTypeDifferenceWeight(Class<?>[] paramTypes, Object[] args) {
   int result = 0;
   for (int i = 0; i < paramTypes.length; i++) {
       //如果不匹配了,那么直接返回个大数了:反正都不匹配
      if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) {
         return Integer.MAX_VALUE;
      }
      if (args[i] != null) {
          //看这里:如果有继承,每个继承差2分,直到继承类和参数指定类相同
         Class<?> paramType = paramTypes[i];
         Class<?> superClass = args[i].getClass().getSuperclass();
         while (superClass != null) {
            if (paramType.equals(superClass)) {
               result = result + 2;
               superClass = null;
            }
            else if (ClassUtils.isAssignable(paramType, superClass)) {
               result = result + 2;
               superClass = superClass.getSuperclass();
            }
            else {
               superClass = null;
            }
         }
          //如果是接口,那么也加一分
         if (paramType.isInterface()) {
            result = result + 1;
         }
      }
   }
   return result;
}

严格模式:

public int getAssignabilityWeight(Class<?>[] paramTypes) {
    //严格模式就会根据继承关系了,而是直接查看找到的参数值是否和指定的匹配
   for (int i = 0; i < paramTypes.length; i++) {
       //有一个不匹配,那么直接返回
      if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) {
         return Integer.MAX_VALUE;
      }
   }
    //匹配中发生一个不匹配
   for (int i = 0; i < paramTypes.length; i++) {
      if (!ClassUtils.isAssignableValue(paramTypes[i], this.rawArguments[i])) {
         return Integer.MAX_VALUE - 512;
      }
   }
    //都匹配了:则返回这个数
   return Integer.MAX_VALUE - 1024;
}

严格模式就少了很多判断了,而且只有三种返回值,在这种情况下,就更可能出现最佳冲突的情况。