likes
comments
collection
share

spring 源码解析之 createBeanInstance

作者站长头像
站长
· 阅读数 36

前言

源码解析

createBeanInstance概述

也是见名知意,这是一个真正创建并初始化一个bean实例的方法,上代码

 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
 ​
    // 根据 beanName与 mbd解析,获取 class 对象,确保获取到正确的bean类,并检查其访问权限是否满足要求
    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());
    }
 ​
    // 是否有bean的 Supplier 接口,如果有,通过回调来创建bean
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
       return obtainFromSupplier(instanceSupplier, beanName, mbd);
    }
 ​
    // 如果工厂方法不为空 则使用工厂方法创建实例
    // 通过 @Bean 注解方法注入的bean 或者xml 配置注入 的BeanDefinition 会存在这个值。而注入这个bean的方法就是工厂方法。后面会详细解读
    if (mbd.getFactoryMethodName() != null) {
       return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
 ​
    // Shortcut when re-creating the same bean...
    // 经过上面的判断,确定没有其他方式创建 bean,以下则使用 bean 的构造函数创建实例
    // 所以打算使用构造函数来进行创建bean。 但是 bean 的构造函数可能有多个,需要确定使用哪一个
    // 这里实际上是一个缓存,resolved 表示构造函数是否已经解析完成;autowireNecessary 表示是否需要自动装配
    // 是否解析完成
    boolean resolved = false;
    // 是否自动装配
    boolean autowireNecessary = false;
    if (args == null) {
       // 锁定构造函数参数锁
       synchronized (mbd.constructorArgumentLock) {
          // 一个类有多个构造参数,每个构造参数都有不同的参数,所以在创建前需根据参数锁定要使用哪个构造参数或工厂方法进行构造
          // 如果 bean 的构造函数或者工厂已经解析过了,那么会保存到mbd.resolvedConstructorOrFactoryMethod,不为空则已经解析过了
          // mbd.resolvedConstructorOrFactoryMethod 用于缓存已解析构造函数或工厂方法的包可见字段
          if (mbd.resolvedConstructorOrFactoryMethod != null) {
             resolved = true;
             autowireNecessary = mbd.constructorArgumentsResolved;
          }
       }
    }
    // 如果已经解析过了 则不用再次解析 使用缓存的数据进行创建 bean
    if (resolved) {
       // 构造函数自动注入
       if (autowireNecessary) {
          return autowireConstructor(beanName, mbd, null, null);
       }
       else {
          // 使用默认的构造函数创建bean
          return instantiateBean(beanName, mbd);
       }
    }
 ​
    // Candidate constructors for autowiring?
    // 来到了这里 就证明没有解析过,需要解析构造函数,并将解析结果保存到mbd.resolvedConstructorOrFactoryMethod
    // 调用 determineConstructorsFromBeanPostProcessors  方法来获取指定的构造函数列表。后面详解
    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.
    // 最终使用默认的构造函数创建bean
    return instantiateBean(beanName, mbd);
 }
  1. 解析Bean类:首先通过resolveBeanClass方法确保获取到正确的bean类,并检查其访问权限是否满足要求。

  2. 使用Supplier接口创建Bean:如果在Bean定义(RootBeanDefinition)中存在instanceSupplier(即实现了Supplier接口的对象),则通过回调此supplier来创建并返回Bean实例。

  3. 工厂方法实例化:检查是否存在工厂方法(由mbd.getFactoryMethodName()指定)。如果有,则调用instantiateUsingFactoryMethod方法,通过工厂方法创建并返回Bean实例。

  4. 构造函数实例化

    • 如果之前已经解析过构造函数或工厂方法(缓存于mbd.resolvedConstructorOrFactoryMethod),则直接根据已解析信息决定采用自动装配还是默认构造函数进行实例化。 否则,继续尝试查找合适的构造函数:
    • 首先通过determineConstructorsFromBeanPostProcessors方法获取经过后处理器处理过的候选构造函数列表。
    • 根据一系列条件(如是否配置了自动装配模式、是否有构造函数参数值等)决定是否进行构造函数自动装配
    • 未找到候选构造函数但有首选构造函数配置(mbd.getPreferredConstructors()),则使用这些首选构造函数进行实例化。
    • 最后,在所有其他方式都无法确定的情况下,使用无参构造函数创建Bean实例

createBeanInstance详细解析

obtainFromSupplier

如果我们为该 bean 给定一个Supplier用来实例化 bean,就可以跳过 spring 默认创建实例化 bean 的方法,直接使用此Supplier进行创建。此方法不是很重要,了解一下就行。

private BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd) {
   // 获取当前正在创建的bean名称并暂存,然后将当前正在创建的bean名称设置为传入的beanName参数
   String outerBean = this.currentlyCreatedBean.get();
   this.currentlyCreatedBean.set(beanName);
   Object instance;

   try {
      // 使用supplier获取 bean 实例
      instance = obtainInstanceFromSupplier(supplier, beanName, mbd);
   }
   catch (Throwable ex) {
      if (ex instanceof BeansException beansException) {
         throw beansException;
      }
      throw new BeanCreationException(beanName, "Instantiation of supplied bean failed", ex);
   }
   finally {
      if (outerBean != null) {
         this.currentlyCreatedBean.set(outerBean);
      }
      else {
         this.currentlyCreatedBean.remove();
      }
   }

   if (instance == null) {
      instance = new NullBean();
   }
   // 将获取到的bean实例封装进一个新的BeanWrapperImpl实例中,并实例化
   BeanWrapper bw = new BeanWrapperImpl(instance);
   initBeanWrapper(bw);
   return bw;
}
  • 获取当前正在创建的bean名称并暂存,然后将当前正在创建的bean名称设置为传入的beanName参数。
  • 调用obtainInstanceFromSupplier方法,使用供应商supplier和传入的beanName及RootBeanDefinition mbd来尝试获取bean实例
  • 果在实例化过程中出现任何异常(包括但不限于BeansException),捕获异常并重新抛出,如果是BeansException则直接抛出,否则包装成BeanCreationException抛出,附带相关的错误信息和原始异常。
  • finally块中恢复原先的当前创建bean名称,以确保线程安全
  • 检查获取到的bean实例是否为空,如果为空,则赋予一个NullBean实例
  • 将获取到的bean实例封装进一个新的BeanWrapperImpl实例中,并调用initBeanWrapper方法对其进行初始化
  • 最后返回初始化完成的BeanWrapper对象

instantiateUsingFactoryMethod

如果RootBeanDefinition 中存在 factoryMethodName 属性,或者在配置文件中配置了factory-method,Spring会尝试使用 instantiateUsingFactoryMethod 方法,根据RootBeanDefinition 中的配置生成bean实例。简单来说,就是如果BeanDefinition 指定了工厂方法,则使用其指定的工厂方法来初始化bean。

这个源码真的又臭又长,也并不重要,就不在这里展示了。具体可以分两点

  • 在 xml配置中,可以使用 factory-beanfactory-method 两个标签可以指定一个类中的方法,Spring会将这个指定的方法的返回值作为bean返回(如果方法是静态方法,则可以不创建factorybean就直接调用,否则需要先将factorybean注入到Spring中)。
  • 对@Bean 注解的解析。在 ConfigurationClassPostProcessor 后处理器中,会对被 @Bean注解修饰的方法进行解析,生成一个 ConfigurationClassBeanDefinitionBeanDefinition。此时BeanDefinition 的 factoryMethodName 正是 @Bean修饰的方法本身。所以这里会调用 instantiateUsingFactoryMethod 方法。通过回调的方式调用 @Bean修饰的方法。并将返回结果注入到Spring容器中。
  • 一直跟着到这里的朋友估计都发现了,spring 会习惯将一个方法分成很多个小方法,这里真的违背了这个了,老实说,我都懒得看下去了。

autowireConstructor概述

autowireConstructor 方法主要用于实现基于类型或构造函数参数的自动装配。当创建一个bean时,该方法首先根据给定的beanNameRootBeanDefinition(合并后的bean定义)查找并确定要使用的构造函数以及其对应的参数。这个源码很长很长很长,基本是我看过 spring 源码中最长的一个方法了,不过跟着注释一步一步看下去,理解不是很难,有些难以理解的也会详细说明的,大可放心。

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

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

   // 候选的构造函数列表
   Constructor<?> constructorToUse = null;
   ArgumentsHolder argsHolderToUse = null;
   // 构造函数最后确定使用的参数
   Object[] argsToUse = null;

   // explicitArgs这个参数是从 getBean这个方法传过来的,如果传过来的参数不为空,则直接使用此参数作为构造函数使用的参数
   if (explicitArgs != null) {
      argsToUse = explicitArgs;
   }
   else {
      // 否则 尝试从 BeanDefinition 中加载缓存的bean构造时需要的参数,下面这几个缓存如果没有数据,在下面的代码会有解析赋值
      Object[] argsToResolve = null;
      synchronized (mbd.constructorArgumentLock) {
         constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
         // 如果构造函数已经缓存,并且已经解析了,直接使用缓存的构造函数
         if (constructorToUse != null && mbd.constructorArgumentsResolved) {
            // Found a cached constructor...
            // 从缓存中获取。这里如果不能获取到完全解析好的参数,则获取尚未解析的参数,进行解析后再赋值给 argsToUse
            // resolvedConstructorArguments 是完全解析好的构造函数参数
            argsToUse = mbd.resolvedConstructorArguments;
            // 如果缓存中有构造函数,但是没有缓存的参数,则证明该构造函数未完全解析
            if (argsToUse == null) {
               // 配置构造函数参数
               // preparedConstructorArguments 是尚未完全解析的构造函数参数
               argsToResolve = mbd.preparedConstructorArguments;
            }
         }
      }
      // 如果解析的参数不为空,则从解析到的参数数组中确认最终构造函数使用的参数
      if (argsToResolve != null) {
         // 解析参数类型,如给定的参数列表为(int,int),这时就会将配置中的("1", "1") 转化为 (1,1)
         // 缓存中的值可能是最终值,也可能是原始值,因为不一定需要类型转换
         argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
      }
   }

   // 如果构造函数 和 构造函数入参都不为空,则可以直接生成bean。否则的话,需要通过一定的规则进行筛选
   if (constructorToUse == null || argsToUse == null) {
      // Take specified constructors, if any.
      // chosenCtors 是候选的构造函数,如果存在候选的构造函数,则跳过这里,否则通过反射获取bean的构造函数集合
      // 获取候选的构造参数列表
      Constructor<?>[] candidates = chosenCtors;
      if (candidates == null) {
         Class<?> beanClass = mbd.getBeanClass();
         try {
            // mbd.isNonPublicAccessAllowed()构造器允许访问,然后通过反射获取bean的构造函数集合
            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);
         }
      }

      // 如果构造函数只有一个 && getBean 没有传参 && 构造参数无参
      // 满足上述三个条件,则无需继续筛选构造函数,直接使用唯一一个构造函数创建 BeanWrapper 并返回即可。
      if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
         Constructor<?> uniqueCandidate = candidates[0];
         // 确定该构造函数无参
         if (uniqueCandidate.getParameterCount() == 0) {
            synchronized (mbd.constructorArgumentLock) {
               // 将解析结束的信息缓存到 mdb中
               // 缓存解析出来的唯一构造函数
               mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
               // 标记构造函数已经完全解析
               mbd.constructorArgumentsResolved = true;
               // 缓存解析好的构造函数参数。这里是空数组 (Object[] EMPTY_ARGS = new Object[0];)
               mbd.resolvedConstructorArguments = EMPTY_ARGS;
            }
            // 调用 instantiate 方法创建对象实例并保存到 bw中 这里因为只有一个无参构造,直接使用无参构造函数创建实例
            bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
            return bw;
         }
      }

      // Need to resolve the constructor.
      //  待选构造函数列表不为null || 需要构造注入,则需要解析。
      //  mbd.getResolvedAutowireMode() 是针对 xml 注入的
      boolean autowiring = (chosenCtors != null ||
            mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
      ConstructorArgumentValues resolvedValues = null;

      // 解析出来的构造函数的个数
      int minNrOfArgs;
      // 如果explicitArgs  不为空,直接使用它作为参数,毕竟是传入的参数,没必要再从进一步解析。
      if (explicitArgs != null) {
         minNrOfArgs = explicitArgs.length;
      }
      else {
         // 获取xml配置文件中的配置的构造函数参数,这里在 xml 加载的时候就已经把相关的 bean 定义解析到了mbd中
         ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
         // 用于承载解析后的构造函数参数的值
         resolvedValues = new ConstructorArgumentValues();
         // 确定解析到的构造函数参数个数并进行类型转换匹配。在下面有详细解读
         minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
      }

      // 寻找最匹配的构造函数
      // 对构造函数列表进行排序: public 构造函数优先参数数量降序,非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();

         // 如果已经找到选用的构造函数 (argstoUse != null) 或者  需要的构造函数的参数个数 小于 当前构造函数参数个数 则终止
         // constructorToUse != null 说明找到了构造函数
         // argsToUse != null 说明参数已经赋值
         // argsToUse.length > parameterCount
         // 即已经找到适配的构造函数(可能不是最终的,但参数数量一定相同), 预选构造函数的参数数量 大于 当前构造函数的数量,可以直接break,因为按照参数数量降序排序,这里如果小于就没有必要继续比较下去
         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;
         }
         // 参数数量不相等,跳过
         if (parameterCount < minNrOfArgs) {
            continue;
         }

         // 到这里说明尚未找到构造函数,且目前的构造函数和需要的构造函数参数个数相同,下面要对类型进行比较。
         ArgumentsHolder argsHolder;
         Class<?>[] paramTypes = candidate.getParameterTypes();
         // 如果构造函数存在参数,resolvedValues 是上面解析后的构造函数,有参则根据 值 构造对应参数类型的参数
         if (resolvedValues != null) {
            try {
               // 获取参数名称
               // 先从 @ConstructorProperties 注解上获取参数名称
               // 如果注解参数为空,再从 @Autowired 注解上获取参数名称
               String[] paramNames = null;
               if (resolvedValues.containsNamedArgument()) {
                  paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
                  // 为null则说明没有使用注解
                  if (paramNames == null) {
                     // 获取参数名称探索器 此接口提供了一个统一的方法来发现方法或构造函数参数的名字
                     ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                     if (pnd != null) {
                        // 获取指定的构造函数的参数名称
                        paramNames = pnd.getParameterNames(candidate);
                     }
                  }
               }
               // 根据类型和数据类型创建 参数持有者
               // 这里会调用  DefaultListableBeanFactory#resolveDependency 方法来解析依赖关系
               // resolvedValues:参数值 paramTypes:参数类型 paramNames:参数名称 getUserDeclaredConstructor(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 ArrayDeque<>(1);
               }
               causes.add(ex);
               continue;
            }
         }
         else {
            // Explicit arguments given -> arguments length must match exactly.
            if (parameterCount != explicitArgs.length) {
               continue;
            }
            // 如果传入的参数与构造函数参数类型相匹配,则根据传入的参数创建一个新的构造器参数解析器
            argsHolder = new ArgumentsHolder(explicitArgs);
         }

         // mbd.isLenientConstructorResolution()是否是宽松模式
         // 类型差异权重
         int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
               argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
         // Choose this constructor if it represents the closest match.
         // 如果当前构造函数的类型差异权重小于最小类型差异权重,则将当前构造函数赋值给构造函数,
         // 参数赋值给参数持有者,最小类型差异权重赋值给最小类型差异权重,ambiguousConstructors赋值为null
         if (typeDiffWeight < minTypeDiffWeight) {
            constructorToUse = candidate;
            argsHolderToUse = argsHolder;
            argsToUse = argsHolder.arguments;
            minTypeDiffWeight = typeDiffWeight;
            ambiguousConstructors = null;
         }
         // 如果typeDiffWeight等于minTypeDiffWeight,且之前已经存在一个最佳匹配(constructorToUse != null),这意味着出现了多个同样适合的构造函数
         else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
            if (ambiguousConstructors == null) {
               ambiguousConstructors = new LinkedHashSet<>();
               ambiguousConstructors.add(constructorToUse);
            }
            // 将当前构造函数添加到ambiguousConstructors集合中
            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 on bean class [" + mbd.getBeanClassName() + "] " +
               "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities. " +
               "You should also check the consistency of arguments when mixing indexed and named arguments, " +
               "especially in case of bean definition inheritance)");
      }
      // ambiguousConstructors != null :说明存在多个最佳匹配即类型差异权重相同
      // mbd.isLenientConstructorResolution():是否是宽松模式
      // 条件成立则说明存在多个构造函数具有相同的匹配度,但按照当前严格的约束条件无法确定一个最佳选择,抛出异常
      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);
      }

      // explicitArgs == null:说明没有传入参数,这意味着需要从bean定义或自动装配机制中解析构造函数参数。
      // argsHolderToUse != null:检查当前是否有一个有效的argsHolderToUse对象,它包含了已经解析好的构造函数参数列表。
      if (explicitArgs == null && argsHolderToUse != null) {
         // 将解析得到的构造函数参数与对应的构造函数以及bean定义(mbd)一起缓存起来
         argsHolderToUse.storeCache(mbd, constructorToUse);
      }
   }

   Assert.state(argsToUse != null, "Unresolved constructor arguments");
   // 使用解析出来的构造函数、构造函数参数列表,创建bean实例
   bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
   return bw;
}
  1. 首先检查是否传入了显式构造函数参数explicitArgs,如果有,则直接使用这些参数来实例化bean,这个参数是从 getBean() 的方法传过来的参数。

  2. 如果没有显式参数,则从RootBeanDefinition中查找已经解析过的构造函数及其参数。如果找到并已完全解析,则直接使用;否则,尝试从缓存的未完全解析参数进行进一步处理。

  3. 若上述步骤仍无法得到构造函数及参数,则通过反射获取类的所有构造函数作为候选,并针对以下情况进行处理:

    • 如果只有一个构造函数,且无参数,直接使用该构造函数创建bean。
    • 否则,resolveConstructorArguments对候选构造函数列表进行筛选,依据传入的参数、配置文件中定义的构造函数参数值,以及自动装配模式(如按类型自动装配),找到最匹配的构造函数及其参数。
  4. 遍历构造函数,对于每个构造函数,方法会解析构造函数参数,包括进行类型转换、依赖注入等操作,以确保传递给构造函数的参数能够正确匹配。这里解释几个概念。

    • ParameterNameDiscoverer:在Java中,编译后的类文件并不直接包含方法参数的名称信息,这使得在运行时通过反射难以直接获取方法参数名。ParameterNameDiscoverer 接口提供了一个统一的方法来发现方法或构造函数参数的名字,这对于支持注解驱动编程和基于注解的依赖注入(如使用@Autowired、@Value等注解)非常重要。例如,在处理@RequestParam、@PathVariable等Spring MVC中的注解时,需要知道参数名才能正确映射HTTP请求中的参数到控制器方法的参数上。
    • 类型差异权重:当Spring尝试为构造函数注入依赖时,它会计算候选bean与构造函数参数之间的类型兼容性。类型差异权重是一种衡量这种兼容性的方法,它考虑了类型转换的成本和复杂度。例如,如果一个构造函数需要String类型的参数,而容器中有一个可用的Object类型的bean,那么类型差异权重可能会反映从Object到String的转换成本(在这种情况下相对较小,因为任何对象都可以转换为字符串)。权重越小通常表示类型匹配得越好
    • 非宽松模式: 在处理构造函数自动装配时,默认情况下Spring可能采用宽松模式,允许某种程度的类型转换以适应构造函数参数。然而,在非宽松模式下,Spring对构造函数参数类型的要求更为严格,只允许直接可赋值的类型匹配,即不允许不必要的类型转换。因此,在非宽松模式下,Spring使用getAssignabilityWeight来计算候选参数与构造函数参数之间的可赋值性权重,仅选择那些无需额外类型转换就能满足要求的构造函数。
  5. 在完成所有解析和匹配工作后,调用instantiate方法利用选定的构造函数和解析好的参数来创建bean实例,并将其封装到BeanWrapperImpl中返回。

autowireConstructor详解

resolveConstructorArguments

resolveConstructorArguments的主要功能是解析和准备给定bean的构造函数参数,以便后续创建bean实例。函数接收多个参数

/**
	 * 解析构造函数参数
	 * Resolve the constructor arguments for this bean into the resolvedValues object.
	 * This may involve looking up other beans.
	 * <p>This method is also used for handling invocations of static factory methods.
	 *
	 * @param beanName       bean名称
	 * @param mbd            mbd
	 * @param bw             bw
	 * @param cargs          包含原始(未解析)的构造函数参数值,这些值可能来自于XML配置或其他bean定义源。
	 * @param resolvedValues 用于存储已解析并准备好传入构造函数的实际参数。
	 * @return int
	 */
	private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
			ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {

		// 获取类型转换器
		TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
		TypeConverter converter = (customConverter != null ? customConverter : bw);
		// BeanDefinitionValueResolver解析和处理bean定义中的属性值以及构造函数参数
		BeanDefinitionValueResolver valueResolver =
				new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);

		// 获取参数个数,这并不一定是最终的参数个数
		int minNrOfArgs = cargs.getArgumentCount();

		// 遍历按索引排列的构造函数参数 indexedArgumentValues
		for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
			int index = entry.getKey();
			if (index < 0) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Invalid constructor argument index: " + index);
			}
			// 这里注意,如果 <constructor-arg> 的index属性大于 参数实际个数,那么Spring会采用index属性的值
			if (index + 1 > minNrOfArgs) {
				minNrOfArgs = index + 1;
			}
			ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
			// 如果类型已经解析过,则保存在 resolvedValues 中
			if (valueHolder.isConverted()) {
				resolvedValues.addIndexedArgumentValue(index, valueHolder);
			}
			else {
				// 否则进行类型解析后再保存到 resolvedValues 中
				Object resolvedValue =
						valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
				// 通过解析参数值、参数类型、参数名称创建resolvedValueHolder,保存到 resolvedValues 中
				ConstructorArgumentValues.ValueHolder resolvedValueHolder =
						new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
				resolvedValueHolder.setSource(valueHolder);
				resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
			}
		}

		// 遍历非按索引排列的构造函数参数 genericArgumentValues
		for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
			// 如果已经解析,则保存到resolvedValues 中
			if (valueHolder.isConverted()) {
				resolvedValues.addGenericArgumentValue(valueHolder);
			}
			else {
				// 否则进行类型解析后再保存到 resolvedValues 中
				Object resolvedValue =
						valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
				ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
						resolvedValue, valueHolder.getType(), valueHolder.getName());
				resolvedValueHolder.setSource(valueHolder);
				// 添加到按非索引排序的参数列表中
				resolvedValues.addGenericArgumentValue(resolvedValueHolder);
			}
		}

		// 返回解析后的构造函数参数个数。
		return minNrOfArgs;
	}
  1. 获取自定义类型转换器或默认使用bw提供的类型转换器。

  2. 创建一个BeanDefinitionValueResolver实例,它负责查找解析bean引用以及其他表达式的值。

  3. 初始化最小参数个数为cargs中记录的参数数量。

  4. 遍历按索引排列的构造函数参数(indexedArgumentValues):

    • 检查索引的有效性,并根据需要更新最小参数个数
    • 对于每个参数,检查是否已经解析过。如果已解析,则直接将值保存到resolvedValues中;
    • 否则,通过resolveValueIfNecessary解析其值,然后以解析后的形式保存。
  5. 遍历非按索引排列的构造函数参数(genericArgumentValues),执行与上述相同的解析和保存操作。

  6. 函数最后返回经过解析调整后的最小构造函数参数个数,这个值将决定在调用实际构造函数时所需的确切参数数量。

  7. 总之,此函数的核心作用在于解析和准备构造函数所需的参数值,确保它们能够在后续创建bean实例的过程中正确地传递给相应的构造函数。

解释一下if (index + 1 > minNrOfArgs) {minNrOfArgs = index + 1;}

minNrOfArgs初始值是基于ConstructorArgumentValues中记录的参数数量,但实际在解析过程中可能会发现更多的参数。例如

public class MyClass {
    public MyClass() {}
    public MyClass(String arg1) {}
    public MyClass(String arg1, String arg2, String arg3) {}
}
<bean id="myBean" class="com.example.MyClass">
    <constructor-arg index="2" value="value3"/>
</bean>
  • 在这个例子中,原始的ConstructorArgumentValues可能只记录了一个参数(因为只有一个显式定义),因此minNrOfArgs初始化时可能是1。
  • 然而,根据XML配置中的index="2"属性,需要调用的是包含三个参数的那个构造函数。
  • 所以,在遍历indexedArgumentValues时,当遇到索引为2的参数时,执行if (index + 1 > minNrOfArgs)条件判断,会更新minNrOfArgs为3,因为它表明至少需要三个参数才能匹配到对应的构造函数。

再解释一下按索引排列非按索引排列的构造函数

按索引排列:这意味着我们明确指定了要注入到构造函数哪个位置(即参数索引)上的值

<bean id="exampleBean" class="com.example.ExampleClass">
    <constructor-arg index="0" value="value1"/>
    <constructor-arg index="2" value="value3"/>
</bean>

这里,ExampleClass可能有一个接受三个参数的构造函数,我们通过index属性指定将"value1"注入到第一个参数,将"value3"注入到第三个参数。

非按索引排列:通常情况下,如果不指定参数索引,Spring会尝试根据类型自动匹配构造函数参数。也就是说,Spring会查找容器中与构造函数参数类型相匹配的Bean,并将其注入。 例如,假设我们有如下类和配置

public class ExampleClass {
    private final String name;
    private final int age;
    private final AnotherDependency dependency;

    public ExampleClass(String name, int age, AnotherDependency dependency) {
        this.name = name;
        this.age = age;
        this.dependency = dependency;
    }
}

<bean id="anotherDependency" class="com.example.AnotherDependency"/>

<bean id="exampleBean" class="com.example.ExampleClass">
    <constructor-arg value="John Doe"/>
    <constructor-arg value="30"/>
    <constructor-arg ref="anotherDependency"/>
</bean>

在这个例子中,虽然没有使用index属性,但Spring能够根据类型推断出"John Doe"对应的是String name,"30"对应的是int age,而ref="anotherDependency"引用的Bean则对应AnotherDependency dependency参数。这是因为Spring会从左到右检查构造函数参数列表并寻找类型匹配项。如果存在多个同类型参数且未指定索引,则无法正确解析。

resolveValueIfNecessary

resolveValueIfNecessary的作用是解析给定的属性值对象,根据其实际类型进行不同方式的处理和依赖注入。确保在创建或装配Bean时正确地解析和替换引用。这个就不放源码了,源码就是根据不同类型使用不同的方式来解析。了解一下就好。

  1. 如果属性值是RuntimeBeanReference类型,则通过resolveReference方法解析并返回对应的Bean实例。
  2. 若为RuntimeBeanNameReference类型,获取并检查Bean名称是否存在,不存在则抛出异常。
  3. 对于BeanDefinitionHolder类型,解析内部Bean定义,并返回相应的Bean实例。
  4. 遇到BeanDefinition类型时,也按照内部Bean的方式进行处理。
  5. 如果属性值是DependencyDescriptor,使用BeanFactory来解析依赖关系,并处理自动装配的Bean。
  6. 对于Managed集合类如ManagedArray、ManagedList、ManagedSet和ManagedMap,递归解析其中可能包含的运行时Bean引用。
  7. 对于ManagedProperties,对键值对进行解析和转换后创建一个新的Properties对象。
  8. TypedStringValue类型会被转换为目标类型,并可能利用TypeConverter进行进一步转换。
  9. NullBean类型直接返回null。
    1. 其他普通对象或null值,调用evaluate方法进行处理(可能是字符串表达式求值)。
  10. 最后,该函数将返回解析后的对象。

determineConstructorsFromBeanPostProcessors

determineConstructorsFromBeanPostProcessors

主要目的是在Spring IoC容器创建bean实例的过程中,借助于SmartInstantiationAwareBeanPostProcessor扩展点来自定义并决定使用哪些构造函数来初始化目标bean。就是说,如果有后置处理器在实例化前介入,会优先选择后置处理器的构造器。

 protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
       throws BeansException {
    // 检查当前应用上下文中是否存在注册的InstantiationAwareBeanPostProcessor或其子接口实现,如SmartInstantiationAwareBeanPostProcessor
    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
       // 遍历所有注册的InstantiationAwareBeanPostProcessor,然后调用determineCandidateConstructors这个方法获取每个后置处理器中符合的构造函数列表
       for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
          Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
          if (ctors != null) {
             return ctors;
          }
       }
    }
    return null;
 }

接下来看到AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors,这个方法是 spring 的默认实现

determineCandidateConstructors

主要功能是从给定的beanClass中确定并返回一个或多个候选构造函数,这些构造函数在Spring框架中用于实例化Bean对象

 public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
       throws BeanCreationException {
 ​
    // 处理和注册带有@Lookup注解的方法
    checkLookupMethods(beanClass, 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 {
                // 所有已声明构造函数
                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注解且标记为“必需”的构造函数
             Constructor<?> requiredConstructor = null;
             // 指的是类中的无参构造函数
             Constructor<?> defaultConstructor = null;
             // 主要构造函数
             // BeanUtils.findPrimaryConstructor(beanClass)返回所提供类的主构造函数。
             // 对于Kotlin类,这将返回对应于Kotlin主构造函数的Java构造函数(如Kotlin规范中所定义的)。
             // 否则,特别是对于非Kotlin类,这只会返回null
             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);
                // 如果该构造方法没有@Autowired注解,那么检查其父类具有相同的参数的构造函数是否具有@Autowired注解
                if (ann == null) {
                   Class<?> userClass = ClassUtils.getUserClass(beanClass);
                   if (userClass != beanClass) {
                      try {
                         //
                         Constructor<?> superCtor =
                               userClass.getDeclaredConstructor(candidate.getParameterTypes());
                         //  在找到的父类构造函数上寻找@Autowired注解
                         ann = findAutowiredAnnotation(superCtor);
                      }
                      catch (NoSuchMethodException ex) {
                         // Simply proceed, no equivalent superclass constructor found...
                      }
                   }
                }
                if (ann != null) {
                   // 检测到类中有多个带有@Autowired注解且标记为“必需”(required)的构造函数时,会抛出BeanCreationException异常
                   if (requiredConstructor != null) {
                      throw new BeanCreationException(beanName,
                            "Invalid autowire-marked constructor: " + candidate +
                            ". Found constructor with 'required' Autowired annotation already: " +
                            requiredConstructor);
                   }
                   // 检查 @Autowired注解中的required属性
                   boolean required = determineRequiredStatus(ann);
                   if (required) {
                      // 进来则说明该构造器为带有 @Autowired(required = true) ,
                      // 但是此时如果候选构造函数列表中存在其他带有@Autowired注解的构造函数时,会抛出BeanCreationException异常
                      if (!candidates.isEmpty()) {
                         throw new BeanCreationException(beanName,
                               "Invalid autowire-marked constructors: " + candidates +
                               ". Found constructor with 'required' Autowired annotation: " +
                               candidate);
                      }
                      // 将此构造函数标记为“必需”构造函数
                      requiredConstructor = candidate;
                   }
                   // 添加到候选构造函数列表中
                   candidates.add(candidate);
                }
                // 如果该构造函数没有参数,则将该构造函数标记为“默认”构造函数
                else if (candidate.getParameterCount() == 0) {
                   defaultConstructor = candidate;
                }
             }
             // 候选构造器不为空
             if (!candidates.isEmpty()) {
                // Add default constructor to list of optional constructors, as fallback.
                // 如果没有“必需”构造函数,则将默认构造函数添加到候选构造函数列表中
                if (requiredConstructor == null) {
                   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));
                   }
                }
                // 缓存构造函数
                candidateConstructors = candidates.toArray(new Constructor<?>[0]);
             }
             // 只有一个构造函数、且构造函数有参数的情况
             else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
             }
             // 如果存在两个非合成构造函数,且第一个构造函数为Kotlin的主构造函数,那么将第二个构造函数添加到候选构造函数列表中
             // primaryConstructor代表是Kotlin的主构造函数,为合成类的构造函数
             // defaultConstructor为默认的构造函数(无参构造),也为合成类的构造函数
             else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                   defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
             }
             else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                candidateConstructors = new Constructor<?>[] {primaryConstructor};
             }
             // 没有存在合适的构造函数
             else {
                candidateConstructors = new Constructor<?>[0];
             }
             this.candidateConstructorsCache.put(beanClass, candidateConstructors);
          }
       }
    }
    return (candidateConstructors.length > 0 ? candidateConstructors : null);
 }

这个方法其实也很好理解,主要就是获取候选的构造器,主要是对三种构造器的判断

requiredConstructor:带有@Autowired注解且标记为“必需”即(@Autowired(required = true))的构造函数

defaultConstructor:默认构造函数(类中的无参构造函数)

primaryConstructor:对于Kotlin类,这将返回对应于Kotlin主构造函数的Java构造函数,否则为 null

instantiate

instantiate这个创建 bean 实例的方法可以稍微了解一下,就是通过了BeanUtils#instantiateClass,然后使用构造器创建一个实例化,解析到最后,构造器确定、参数列表确定、参数值也确定了、就能直接创建一个实例了

spring 源码解析之 createBeanInstance

转载自:https://juejin.cn/post/7328753414725287936
评论
请登录