Spring IOC - 推断构造方法

一、前言

        上文解析了Bean生命周期的实例化阶段,其中bean真正开始实例化的核心代码位于方法AbstractAutowireCapableBeanFactory#createBeanInstance中,这里也是spring推断构造方法的核心所在。

二、整体介绍

        首先看下方法的源码及注释如下,下面我们再逐行解析。

// 使用适当的实例化策略为指定的bean创建一个新实例:工厂方法、构造函数自动装配或简单实例化
// 创建bean的实例,这里也是spring推断构造方法的核心所在
// args:表示程序员通过getBean传入的参数,如果使用getBean(Class<?> requireType,Object[] args),那么传入的参数就会传入到这里
// 这个参数是用于构造函数或工厂方法调用的显示参数
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
   // 获取bean的Class对象
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
   }

   // 通过bd中提供的instanceSupplier来获取一个对象
   // 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   // 如果工厂方法不为null,则使用工厂方法初始化策略
   // bd中提供了factoryMethodsName属性,那么要使用工厂方法的方法来创建对象
   // 工厂方法又会区分静态工厂方法跟实例工厂方法
   if (mbd.getFactoryMethodName() != null) {
      // 如果使用了工厂方法,则调用工厂方法创建bean实例。@Bean注解创建的实例会进入这里
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // Shortcut when re-creating the same bean...
   // 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了
   // 是否推断过构造函数
   boolean resolved = false;
   // 构造函数是否需要进行注入
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         // 一个类里面有多个构造函数,每个构造函数都有不同的参数,所以调用前需根据参数锁定要调用
         // 的构造函数或工厂方法
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   // 如果已经解析过则使用解析好的构造函数方法,不需要再次锁定
   if (resolved) {
      if (autowireNecessary) {
         // 构造函数自动注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // 使用默认构造函数进行构造
         return instantiateBean(beanName, mbd);
      }
   }

   // Candidate constructors for autowiring?
   // 需要根据参数解析构造函数
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      // 构造函数自动注入
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // Preferred constructors for default construction?
   // 获取首选构造函数,作为默认构造器
   ctors = mbd.getPreferredConstructors();
   if (ctors != null) {
      return autowireConstructor(beanName, mbd, ctors, null);
   }

   // No special handling: simply use no-arg constructor.
   // 没有什么特殊的处理:简单使用无参构造方法
   return instantiateBean(beanName, mbd);
}

        总体流程总结如下:

  1. AbstractAutowireCapableBeanFactory类中的createBeanInstance()方法会去创建一个Bean实例
  2. 根据BeanDefinition加载类得到Class对象
  3. 如果BeanDefinition绑定了一个Supplier,那就调用Supplier的get方法得到一个对象并直接返回
  4. 如果BeanDefinition中存在factoryMethodName,那么就调用该工厂方法得到一个bean对象并返回
  5. 如果BeanDefinition已经自动构造过了,那就调用autowireConstructor()自动构造一个对象
  6. 调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方法得到哪些构造方法是可以用的
  7. 如果存在可用得构造方法,或者当前BeanDefinition的autowired是AUTOWIRE_CONSTRUCTOR,或者BeanDefinition中指定了构造方法参数值,或者创建Bean的时候指定了构造方法参数值,那么就调用**autowireConstructor()**方法自动构造一个对象
  8. 最后,如果不是上述情况,就根据无参的构造方法实例化一个对象

三、Supplier

        Supplier是Spring 用来创建bean的一种方式,但是不常见。即将beanDefiniton属性instanceSupplier设置一个可以返回实例的方法,那么通过该beanDefinition生成实例bean时,会调用Supplier的getObject方法直接返回。示例如下:

public class Analsis {

   public static void main(String[] args) {
      DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
      AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
      beanDefinition.setBeanClass(User.class);
      beanDefinition.setInstanceSupplier(Teacher::new);
      beanFactory.registerBeanDefinition("user", beanDefinition);
      System.out.println(beanFactory.getBean("user"));
   }
}

        示例返回结果为:com.test.Teacher@6d4b1c02,虽然设置的beanClass属性为User.class,但是返回的bean实例还是Teacher实例。

四、@Bean

        这里阐述的是通过beanDefinition中的factoryMethodName属性来创建bean实例。@Bean标记的方法名就是factoryMethodName,其所在的父类名称就是属性factoryBeanName。通过@Bean标记的实例,其实在解析生成BeanDefinition时,就已经对关键属性进行赋值了,后续的创建过程无非就是根据其属性来实例化,这里有个关键属性:factoryMethodToIntrospect,即通过内省获取的工厂方法,其实到最后就是通过反射机制调用该方法创建实例。

五、推动构造函数

        这里的逻辑是一个扩展点,即调用实现了SmartInstantiationAwareBeanPostProcessor接口的determineCandidateConstructors方法。而AutowiredAnnotationBeanPostProcessor实现了该接口,其源码及注释如下:

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
      throws BeanCreationException {

   // Let's check for lookup methods here...
   if (!this.lookupMethodsChecked.contains(beanName)) {
      if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
         try {
            Class<?> targetClass = beanClass;
            do {
               //遍历targetClass中的method,查看是否写了@Lookup方法
               ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                  Lookup lookup = method.getAnnotation(Lookup.class);
                  if (lookup != null) {
                     Assert.state(this.beanFactory != null, "No BeanFactory available");
                     //将当前method封装成LookOverride并设置到BeanDefinition的methodOverrides中
                     LookupOverride override = new LookupOverride(method, lookup.value());
                     try {
                        RootBeanDefinition mbd = (RootBeanDefinition)
                              this.beanFactory.getMergedBeanDefinition(beanName);
                        mbd.getMethodOverrides().addOverride(override);
                     }
                     catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(beanName,
                              "Cannot apply @Lookup to beans without corresponding bean definition");
                     }
                  }
               });
               targetClass = targetClass.getSuperclass();
            }
            while (targetClass != null && targetClass != Object.class);

         }
         catch (IllegalStateException ex) {
            throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
         }
      }
      this.lookupMethodsChecked.add(beanName);
   }

   // Quick check on the concurrent map first, with minimal locking.
   //决定一组构造方法的逻辑代码,candidateConstructorsCache是一个构造方法候选者的集合,就是说如果找到了符合条件的构造方法
   //都会缓存到这个集合中,表示是符合条件的构造方法的候选者集合
   //这里先从缓存中去取,如果缓存中没有,就去推断出符合的记录添加到缓存中
   Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
   if (candidateConstructors == null) {
      // Fully synchronized resolution now...
      synchronized (this.candidateConstructorsCache) {
         //先从缓存中去取,如果有,就直接返回,如果没有,就去找
         candidateConstructors = this.candidateConstructorsCache.get(beanClass);
         if (candidateConstructors == null) {
            Constructor<?>[] rawCandidates;
            try {
               //这个是得到一个Bean中的声明的所有的构造方法列表,是一个数组,数组里面是bean中的所有构造方法
               rawCandidates = beanClass.getDeclaredConstructors();
            }
            catch (Throwable ex) {
               throw new BeanCreationException(beanName,
                     "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                     "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
            }
            //构建一个候选者列表的构造方法集合
            List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
            //用来记录@AutoWired标记并且required为true的构造方法,一个类中只能有一个required为true的构造方法
            Constructor<?> requiredConstructor = null;
            //用来记录默认无参构造方法
            Constructor<?> defaultConstructor = null;
            //kotlin相关,不用管
            Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
            int nonSyntheticConstructors = 0;
            //遍历每个构造方法
            for (Constructor<?> candidate : rawCandidates) {
               if (!candidate.isSynthetic()) {
                  //记录下一普通构造方法
                  nonSyntheticConstructors++;
               }
               else if (primaryConstructor != null) {
                  continue;
               }
               //当前遍历的构造方法是否被@AutoWired注解标记
               MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
               if (ann == null) {
                  //如果beanClass是代理类,则得到被代理类的类型
                  //然后去看被代理类中对应的构造方法是否有@AutoWired注解
                  Class<?> userClass = ClassUtils.getUserClass(beanClass);
                  if (userClass != beanClass) {
                     try {
                        Constructor<?> superCtor =
                              userClass.getDeclaredConstructor(candidate.getParameterTypes());
                        ann = findAutowiredAnnotation(superCtor);
                     }
                     catch (NoSuchMethodException ex) {
                        // Simply proceed, no equivalent superclass constructor found...
                     }
                  }
               }
               //当前构造方法加了@AutoWired注解
               if (ann != null) {
                  //整个类中如果有一个required为true的构造方法,那就不能有其他的加了@Autowired的构造方法
                  if (requiredConstructor != null) {
                     throw new BeanCreationException(beanName,
                           "Invalid autowire-marked constructor: " + candidate +
                           ". Found constructor with 'required' Autowired annotation already: " +
                           requiredConstructor);
                  }
                  boolean required = determineRequiredStatus(ann);
                  //required为true
                  if (required) {
                     //如果已经有@AutoWired注解标注的构造方法,则抛错
                     if (!candidates.isEmpty()) {
                        throw new BeanCreationException(beanName,
                              "Invalid autowire-marked constructors: " + candidates +
                              ". Found constructor with 'required' Autowired annotation: " +
                              candidate);
                     }
                     //记录唯一一个required为true的构造方法
                     requiredConstructor = candidate;
                  }
                  //记录所有加了@AutoWired的构造方法,不管required为true还是false
                  //如果默认无参构造方法上也加了@Autowired注解,那么也会加到candidates中
                  candidates.add(candidate);
               }
               //如果没有被@AutoWired注解标记,并且是无参的,则赋值给defaultConstructor
               else if (candidate.getParameterCount() == 0) {
                  //记录唯一一个无参的构造方法
                  defaultConstructor = candidate;
               }
               //从以上代码可以看出,一个类中要么只能有一个required=true的构造方法,要么只能有一个或多个required=false的构造方法
            }
            //循环完所有的构造方法
            //1.candidates要么为空,也就是没有被@Autowired标记的构造方法
            //2.candidates中只有一个required=true的构造方法
            //3.candidates中是所有required=false的构造方法

            //如果candidates不为空,那么就是有@Autowired标记的构造方法
            if (!candidates.isEmpty()) {
               // Add default constructor to list of optional constructors, as fallback.
               //如果不存在一个required=true的构造方法,那么candidates中都是required=false的构造方法
               if (requiredConstructor == null) {
                  //如果存在无参构造方法将无参构造方法放到candidates中
                  if (defaultConstructor != null) {
                     candidates.add(defaultConstructor);
                  }
                  else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                     logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                           "': single autowire-marked constructor flagged as optional - " +
                           "this constructor is effectively required since there is no " +
                           "default constructor to fall back to: " + candidates.get(0));
                  }
               }
               //1.如果只存在一个required=true的构造方法,那么只有这一个是合格的
               //2.如果有多个required=false的构造方法,那么所有的required=false的构造方法都是合格的
               //此时如果有无参构造方法,那么所有required=false和无参构造方法都是合格的
               candidateConstructors = candidates.toArray(new Constructor<?>[0]);
            }
            // 如果没有加了@AutoWired注解的构造方法,并且类中只有一个构造方法,并且该构造方法是有参的,这个构造方法也是合格的
            else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
               candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
            }
            // primaryConstructor 不用管kotlin
            else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                  defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
               candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
            }
            // primaryConstructor 不用管kotlin
            else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
               candidateConstructors = new Constructor<?>[] {primaryConstructor};
            }
            else {
               // 如果有多个有参、并且没有添加@AutoWired的构造方法,是返回空的
               candidateConstructors = new Constructor<?>[0];
            }
            this.candidateConstructorsCache.put(beanClass, candidateConstructors);
         }
      }
   }
   return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

        可以得出一个结论:Autowired注解的required属性默认为true,一个类中要么只能有一个required=true的构造方法,要么只能有一个或多个required=false的构造方法,没有标注Autowired的方法可以与他们混合存在。

六、带参实例化

        这里需要对构造函数参数进行解析和推断,从而决定调用哪个构造函数,即通过构造函数参数值去匹配构造函数,其源码和注释,以及逻辑总结如下:

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
      @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
    //实例化一个beanWrapperImpl类对象
   BeanWrapperImpl bw = new BeanWrapperImpl();
    //初始化bw,这里的BeanFactory来自于AbstractAutowireCapableBeanFactory
   this.beanFactory.initBeanWrapper(bw);
 
    
   Constructor<?> constructorToUse = null;
   ArgumentsHolder argsHolderToUse = null;
   Object[] argsToUse = null;
 
    //explicitArgs不为空,说明用户指定了构造方法的参数,直接拿来使用
   if (explicitArgs != null) {
      argsToUse = explicitArgs;
   }
   else {
      Object[] argsToResolve = null;
      synchronized (mbd.constructorArgumentLock) {
            //尝试从mbd的缓存中拿取构造方法
         constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
            //构造方法不为空并且构造方法已经解析 
         if (constructorToUse != null && mbd.constructorArgumentsResolved) {
            // Found a cached constructor...
            //直接从mbd缓存中拿取构造方法的参数
            argsToUse = mbd.resolvedConstructorArguments;
            if (argsToUse == null) {
                //如果没有拿到构造方法的参数,就获取缓存中的配置文件的参数
               argsToResolve = mbd.preparedConstructorArguments;
            }
         }
      }
      if (argsToResolve != null) {
            //正确拿到配置文件的参数之后,对参数进行解析,最后生成构造方法的参数
         argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
      }
   }
 
    //如果没有拿到构造方法,就说明没有bean进行过解析,需要去关联对应的bean的构造器
   if (constructorToUse == null || argsToUse == null) {
      // Take specified constructors, if any.
        //获取传入的构造器
      Constructor<?>[] candidates = chosenCtors;
        //如果构造器不为空
      if (candidates == null) {
                //获取bean的类型
         Class<?> beanClass = mbd.getBeanClass();
         try {
            //判断是否允许非公开访问,如果允许就获取所有的构造方法,如果不允许就获取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);
         }
      }
 
        //如果只有一个构造方法并且,指定参数为空,并且配置文件里面没有构造方法的参数值
      if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
        //获取唯一的构造方法
         Constructor<?> uniqueCandidate = candidates[0];
        //判断这个构造方法的参数个数为0,这个构造方式 就是默认的构造方法
         if (uniqueCandidate.getParameterCount() == 0) {
            synchronized (mbd.constructorArgumentLock) {
                            //记录到mbd的缓存中去
               mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
               mbd.constructorArgumentsResolved = true;
               mbd.resolvedConstructorArguments = EMPTY_ARGS;
            }
            //初始化bean, 并且设置到bw(bean 的包装对象)中去
            bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
            return bw;
         }
      }
 
 
      // Need to resolve the constructor.
        //这里判断了是否是自动导入的
      boolean autowiring = (chosenCtors != null ||
            mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
      ConstructorArgumentValues resolvedValues = null;
 
 
      int minNrOfArgs;
      if (explicitArgs != null) {
            //获取用户传入参数的个数
         minNrOfArgs = explicitArgs.length;
      }
      else {
            //从配置文件中拿到参数的值
         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;
      LinkedList<UnsatisfiedDependencyException> causes = null;
 
        //逐一遍历所有的构造方法
      for (Constructor<?> candidate : candidates) {
        //获取构造方法的参数类型
         Class<?>[] paramTypes = candidate.getParameterTypes();
 
            //这里的判断构造方法和构造方法参数 都不是空,又由于之前对构造方法做了排序。所以在使用的参数的个数已经大于当前构造方法的参数个数的时候,实际上已经取到了想要的构造方法。
         if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
            // Already found greedy constructor that can be satisfied ->
            // do not look any further, there are only less greedy constructors left.
            break;
         }
            //通过构造方法的参数个数 快速的做一个判断
         if (paramTypes.length < minNrOfArgs) {
            continue;
         }
 
 
         ArgumentsHolder argsHolder;
         if (resolvedValues != null) {
            try {
               String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
               if (paramNames == null) {
                    //参数名冲突的解决器
                  ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                  if (pnd != null) {
                        //获取参数的名称
                     paramNames = pnd.getParameterNames(candidate);
                  }
               }
                //用获取到的参数名和和构造函数以及参数类型生成用户创建构造函数使用的构造参数数组,数组里会同时持有原始的参数列表和构造后的参数列表。
               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 LinkedList<>();
               }
               causes.add(ex);
              continue;
 
            }
         }
         else {
            // Explicit arguments given -> arguments length must match exactly.
            //用户指定了构造方法的参数时,直接用获取到的参数类型数量与用户传参数量比较,不等于直接跳过当前的构造方法
            if (paramTypes.length != explicitArgs.length) {
               continue;
            }
            argsHolder = new ArgumentsHolder(explicitArgs);
         }
 
            //isLenientConstructorResolution()判断策略是否宽松
            //宽松策略下,使用spring构造的参数数组的类型和获取到的构造方法的参数类型进行对比。
            //严格策略下,还需要检查能否将构造方法的参数复制到对应的属性中
            //会返回一个数值,作为构造方法和参数的差异值
         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);
         }
      }
 
        //异常的判断
      if (constructorToUse == null) {
         if (causes != null) {
            UnsatisfiedDependencyException ex = causes.removeLast();
            for (Exception cause : causes) {
               this.beanFactory.onSuppressedException(cause);
            }
            throw ex;
         }
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Could not resolve matching constructor " +
               "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
      }
      else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Ambiguous constructor matches found in bean '" + beanName + "' " +
               "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
               ambiguousConstructors);
      }
 
        //做一个缓存,方便下次的使用
      if (explicitArgs == null && argsHolderToUse != null) {
         argsHolderToUse.storeCache(mbd, constructorToUse);
      }
   }
 
    //用上面得到的构造器和参数来反射创建bean实例,并放到BeanWrapperImpl对象中然后返回
   Assert.state(argsToUse != null, "Unresolved constructor arguments");
   bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
   return bw;
}

        这个方法的代码量很大,逻辑也比较复杂。我们将逻辑简单拆分,整理成以下几个方面:

1. 构造方法参数值的确定

        1)根据explicitArgs参数判断。

        如果参入的参数explicitArgs不为空,就可以直接确定下参数,因为explicitArgs参数是在调用Bean的时候用户指定的,在BeanFactory类中有这样一个方法:Object getBean(String name, Object... args)

        在获取bean的时候,用户不但可以指定bean的名称还可以指定bean所对应类的构造方法或者工厂方法的参数,主要用于静态工厂方法的调用,这里则是需要给定完全匹配的参数,所以,可以判定explicitArgs不为空,就是构造方法的参数就是它。

        2)缓存中获取

        除此之外,确定参数的办法如果之前已经分析过,构造方法参数已经有记录在缓存中,那么便可以直接拿来使用。但是这里缓存的参数可以是最终的类型也可能是初始的类型。例如:构造方法需要的参数是int类型的1,但是原始参数可能是String类型的“1”,那么即使从缓存中获取到了参数,也需要经过类型转换器来保证与构造方法的参数类型一致。

        3)配置文件获取

        在前两个方法都没法获取到参数的时候,就只能开始新一轮的分析。

从配置文件中获取配置到构造方法的信息开始,经过之前的分析,spring中的配置文件的信息会被转换成通用的BeanDefinition实例,也就是参数mbd,通过调用mbd.getConstructorArgumentValues()来获取配置的构造函数信息。拿到配置中的信息便可以获取到每个参数对应得值。

        4)通过依赖注入获取

        这里涉及到依赖的解析了,在后面文章属性注入详细讲解。

2.构造方法的确定

        经过第一个步之后确定了构造方法的参数,接下来就是要根据构造方法的参数来找到对应的构造方法,匹配的方法就是根据参数的个数对比,在匹配之前需要对构造方法按照public构造方法优先、参数数量降序排列、非public构造方法参数降序排列。这样可以在遍历的情况下迅速的判断出构造方法参数个数是否符合条件。

        由于在配置文件中并不是唯一限制使用参数位置索引的方式去创建,还同时支持指定参数名进行设定参数值的情况,如<constructor-arg name="aa">,这种情况下就需要先确定构造方法中的参数名。

        获取参数名可以用两种方式,一种是通用注解的方式直接获取,另一种就是使用Spring中提供的工具类ParameterNameDiscoverer来获取。构造方法、参数名、参数类型、参数值确定之后却可以确定构造方法。

3.根据参数类型转换对应参数的类型。

4.构造函数不确定性验证

        有的时候根据之前的筛选并无法直接确定需要的构造方法,最后根据匹配度做一次验证

5.根据实例化策略以及得到的构造方法参数对bean进行实例化。

七、无参实例化

        这个逻辑就比较简单了,其对应的方法为SimpleInstantiationStrategy#instatance,通过class对象获取参数个数为0的构造方法来实例化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/160124.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

“具有分布式能源资源的多个智能家庭的能源管理的联邦强化学习”文章学习四——基于联邦深度学习的多智能家居能源管理

一、用于家庭能源管理的FRL算法 在本节中&#xff0c;我们将阐述提出的FRL算法&#xff08;算法1&#xff09;&#xff0c;该算法以分布式方式调度多个智能家庭的能量消耗。在提出的FRL框架中&#xff0c;LHEMS和GS相互迭代并有效训练LHEMS的模型。我们考虑了由LHEMS控制的空调…

vivado产生报告阅读分析7-时序报告3

1、“ Timing Summary Report ”详情 “ Timing Summary Report ” &#xff08; 时序汇总报告 &#xff09; 包含下列部分 &#xff1a; • “ General Information ”部分 • “ Timer Settings ”部分 • “ Design Timing Summary ”部分 • “ Clock Summary ”部…

公网使用PLSQL远程连接Oracle数据库【内网穿透】

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

Linux常用命令——bzcat命令

在线Linux命令查询工具 bzcat 解压缩指定的.bz2文件 补充说明 bzcat命令解压缩指定的.bz2文件&#xff0c;并显示解压缩后的文件内容。保留原压缩文件&#xff0c;并且不生成解压缩后的文件。 语法 bzcat(参数)参数 .bz2压缩文件&#xff1a;指定要显示内容的.bz2压缩文…

使用requests库进行网络爬虫:IP请求错误的解决方法

目录 引言 一、了解requests库 二、遇到的问题 三、解决方法 1、随机化IP地址 2、减少请求频率 3、使用User Agent模拟浏览器行为 4、使用Cookies 四、注意事项 五、使用代理池 六、总结 引言 在利用Python的requests库进行网络爬虫操作时&#xff0c;我们有时会遇…

Hangfire.Pro 3.0 Crack

Hangfire.Pro 有限的存储支持 Hangfire Pro 是一组扩展包&#xff0c;允许使用批处理创建复杂的后台作业工作流程&#xff0c;并提供对超快速Redis作为作业存储的支持 请注意&#xff0c;仅在使用Hangfire.SqlServer、Hangfire.Pro.Redis或Hangfire.InMemory包作为作业存储时才…

贝加莱MQTT功能

贝加莱实现MQTT Client端的功能库和例程 导入库和例程&#xff0c;AS Logical View中分别通过Add Object—Library&#xff0c;Add—Program插入MQTT库和例程。 将例程Sample放置于CPU循环周期中 定义证书存放路径&#xff0c;在AS Physical View 中&#xff0c;右击PLC—Con…

C++--STL总结

参考教程&#xff1a;黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难_哔哩哔哩_bilibili 软件界一直希望建立一种可重复利用的东西&#xff0c;C的面向对象和泛型编程思想&#xff0c;目的就是复用性的提升。 大多情况下&#xff0c;数据结构和算法都未能有一套标准,…

开关电源测试之输出暂态响应测试标准及方法详解

暂态响应是指在接收到输入信号后&#xff0c;输出信号在短时间内产生的变化。开关电源输出暂态响应测试是为了检测输出负载快速变化时&#xff0c;输出电压跟随变动的稳定性。 开关电源输出暂态响应怎么测试&#xff1f; 测试目的&#xff1a;测试S.M.P.S.输出负载快速变化时&a…

python django 小程序点餐源码

开发工具&#xff1a; PyCharm mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 微信小程序 代码注释齐全&#xff0c;没有多余代码&#xff0c;适合学习(毕设)&#xff0c;二次开发&#xff0c;包含论文技术相关文档。 功能介绍&#xff1a…

视百年眼科青少年近视防控中心正式启动,构建近视防控新格局

11月16日上午&#xff0c;广州视百年眼科青少年近视防控中心启动仪式在门诊顺利举行。视百年眼科董事长孙联合、技术院长李国保、视光中心负责人肖萧、视光主任刘得圳出席会议并对如何做好青少年近视防控工作作出了工作部署。 视百年眼科孙董事长在会上强调&#xff0c;青少年是…

什么是单域名SSL安全证书?

单域名证书是什么&#xff1f; 单域名证书是指只包含一个具体域名的SSL/TLS证书&#xff0c;它可以用于保护单个主机名的HTTPS通信。例如&#xff0c;如果您有一个网站http://www.example.com&#xff0c;则单域名证书将仅为该域名颁发。 这种证书在保护单个域的安全方面很有…

C++多态原理揭秘

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

天猫精灵/小爱同学+巴法云+Openwrt控制局电脑/群晖开关机

天猫精灵/小爱同学巴法云Openwrt控制局电脑/群晖开关机 事情的起因实战环境开始发车1.天猫精灵/小爱同学 连接 八法云 2.openwrt3.docker环节注意:sshpass 要先使用 ssh命令登陆一下你要唤醒或者远程关机的设备,不然可能因为一个登陆提示你是否登陆的yes/no导致程序没有反应,然…

任正非说:公司要逐步实行分灶吃饭,我们在管理上不能过于整齐划一,否则缺少战斗力。

你好&#xff01;这是华研荟【任正非说】系列的第42篇文章&#xff0c;让我们聆听任正非先生的真知灼见&#xff0c;学习华为的管理思想和管理理念。 一、我们必须在混沌中寻找战略方向。规划就是要抓住机会点&#xff0c;委员会是火花荟萃的地方&#xff0c;它预研的方向是可做…

ESP32 MicroPython LCD显示实验⑤

ESP32 MicroPython LCD显示实验⑤ 1、实验目的2、实验平台3、实验内容4、参考代码5、实验结果 1、实验目的 LCD显示屏显示中英文字符、显示图片 2、实验平台 智能小车(配备显示屏) 3、实验内容 小车配有2.0寸的TFT彩屏&#xff0c;内置有中文GBK字库&#xff0c;可以显示中…

值得你一生收藏的BMW宝马汽车底盘代号各个版本说明,方便今后查阅使用!

很少有汽车品牌像宝马一样&#xff0c;本属于内部交流使用的底盘代号&#xff08;Development Code&#xff09;&#xff0c;最终延伸为粉丝群体用以精准定位某一年代某一款车型的通用语。随着宝马加速推出新产品&#xff0c;每一年的底盘代号都在更新。你挚爱的强哥现将宝马所…

echarts 三角锥形柱状图 + 带阴影的折线图示例

该示例有如下几个特点&#xff1a; ①三角锥形折线图 ②折线图自带阴影 ③三角锥形鼠标放置时颜色改变 ④数据随着鼠标移动而展示 ⑤鼠标放置时tooltip样式自定义&#xff08;echarts 实现tooltip提示框样式自定义-CSDN博客&#xff09; 代码如下&#xff1a; this.options …

鸿蒙ToastDialog内嵌一个xml页面会弹跳到一个新页面《解决》

ToastDialog 土司组件 1.问题展示2.代码展示3.问题分析 1.问题展示 0.理想效果 错误效果: 1.首页展示页面 (未点击按钮前) 2.点击按钮之后&#xff0c;弹窗不在同一个位置 2.代码展示 1.点击按钮的 <?xml version"1.0" encoding"utf-8"?> <…

HTTP1.0协议详解

前言主要特点存在的不足与HTTP1.1的区别在Java中应用HTTP1.0协议知识拓展 前言 HTTP是由蒂姆伯纳斯李&#xff08;Tim Berners-Lee&#xff09;爵士创造的。他在1989年提出了一个构想&#xff0c;借助多文档之间相互关联形成的超文本&#xff08;HyperText&#xff09;&#x…