这节主要是第一篇,讲一讲Spring怎么选择你提供的构造函数的(多个),而提供了多个怎么选择是下一节的内容

抛出问题:

@Component
public class IndexService {
   @Autowired
   OrderDao orderDao;
   public IndexService() {
   }
   public IndexService(OrderDao orderDao) {
      this.orderDao = orderDao;
   }
   public IndexService(OrderDao orderDao, Luban luban) {
   }
}

这样一个类,Spring在实例化的时候会用哪个构造方法,大部分人应该会猜是无参构造方法,可以说是对的,但不完全对
再换一个:

@Component
public class IndexService {
   @Autowired
   OrderDao orderDao;
   public IndexService(OrderDao orderDao) {
      this.orderDao = orderDao;
   }
   public IndexService(OrderDao orderDao, Luban luban) {
   }
}

如果是这样呢?
Spring还是会选择无参的,小伙伴可以自行尝试

定位源码

避免有些小伙伴没看过Spring源码,这里从最最开始的源头开始摘录处理
(其实这也是实例化Bean的路径。。)

代表一个方法
org.springframework.context.support.AbstractApplicationContext#refresh
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

然后就到了我们今天需要看的源码了,先来个概览

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
   Class<?> beanClass = resolveBeanClass(mbd, beanName);
   /**
    * 检测一个类的访问权限spring默认情况下对于非public的类是允许访问的。
    */
   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());
   }
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }
   /**
    *
    * 如果工厂方法不为空,则通过工厂方法构建 bean 对象
    @Bean其实就是通过这种方法来实例化的
    */
   if (mbd.getFactoryMethodName() != null)  {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }
   // Shortcut when re-creating the same bean...
   /**
    * 从spring的原始注释可以知道这个是一个Shortcut,什么意思呢?
    * 当多次构建同一个 bean 时,可以使用这个Shortcut,
    * 也就是说不在需要次推断应该使用哪种方式构造bean
    *  比如在多次构建同一个prototype类型的 bean 时,就可以走此处的hortcut
    * 这里的 resolved 和 mbd.constructorArgumentsResolved 将会在 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) {
         // 通过构造方法自动装配的方式构造 bean 对象
         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);
   }
   // No special handling: simply use no-arg constructor.
   //使用默认的无参构造方法进行初始化
   return instantiateBean(beanName, mbd);
}

我们前面都不看,只看一行determineConstructorsFromBeanPostProcessors这个方法。determineConstructorsFromBeanPostProcessors这个方法就是今天的重头戏,他会返回一个 Constructor<?>[],这个就是Spring会选择的构造器数组,返回一个数组?不要紧,Spring会在autowireConstructor里选择一个来进行初始化,怎么选择这就是第二节的内容

Spring怎么判断类有几个构造器

determineConstructorsFromBeanPostProcessors源码分析

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
      throws BeanCreationException {
   // Let's check for lookup methods here..
   /**
    * 处理含有@Lookup注解的方法
    * 如果集合中没有BeanName,则走一遍Bean中所有的方法,过滤是否含有Lookup方法
    */
   if (!this.lookupMethodsChecked.contains(beanName)) {
      try {
         /**
          * 在方法中循环过滤所有的方法
          */
         ReflectionUtils.doWithMethods(beanClass, method -> {
            /**
             * 获取method上的@Lookup注解
             */
            Lookup lookup = method.getAnnotation(Lookup.class);
            /**
             * 存在此注解的话,就将方法和注解中的内容构建LookupOverride对象,设置进BeanDefinition中
             */
            if (lookup != null) {
               Assert.state(this.beanFactory != null, "No BeanFactory available");
               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");
               }
            }
         });
      }
      catch (IllegalStateException ex) {
         throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
      }
      /**
       * 无论对象中是否含有@Lookup方法,过滤完成后都会放到集合中,证明此Bean已经检查完@Lookup注解了
       */
      this.lookupMethodsChecked.add(beanName);
   }
   // Quick check on the concurrent map first, with minimal locking.
   /**
    * 从缓存中拿构造函数,不存在的话就进入代码块中再拿一遍,还不存在的话就进行下方的逻辑
    * 双重检查
    */
   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);
            /**
             * 用户指定的必须用的构造函数
             */
            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;
               }
               //find加了@Autowired的构造函数
               AnnotationAttributes ann = findAutowiredAnnotation(candidate);
               /**
                * 注解不存在,则再通过方法获取用户类,如果是用户类则返回用户类,还判断了CGLIB情况,
                * CGLIB情况则返回目标类,然后获取参数一致的构造函数再获取注解
                */
               if (ann == null) {
                  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...
                     }
                  }
               }
               /**
                * 构造函数上存在注解
                */
               if (ann != null) {
                  if (requiredConstructor != null) {
                     throw new BeanCreationException(beanName,
                           "Invalid autowire-marked constructor: " + candidate +
                           ". Found constructor with 'required' Autowired annotation already: " +
                           requiredConstructor);
                  }
                  /**
                   * 获取@Autowired注解中required属性的值
                   * 值得注意的是如果是默认的即没加required
                   * 这里返回的也会是true
                   */
                  boolean required = determineRequiredStatus(ann);
                  if (required) {
                     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;
               }
            }
            /**
             * 不为空,则直接用candidates的
             */
            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.isWarnEnabled()) {
                     logger.warn("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]);
            }
            /**
             * 如果只有一个构造函数,且参数个数大于0的。,那么就选用它
             */
            else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
               candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
            }
            /**
             * 如果有两个,然后primaryConstructor和defaultConstructor都不为null
             * 且两个不相等,则两个都作为返回值
             */
            else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                  defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
               candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
            }
            /**
             * 如果只有primaryConstructor,且primaryConstructor不为null,则使用他
             */
            else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
               candidateConstructors = new Constructor<?>[] {primaryConstructor};
            }
            /**
             * 啥都不满足就是没有
             * 即Spring会用他自己的默认的构造函数(其实就是无参构造)
             */
            else {
               candidateConstructors = new Constructor<?>[0];
            }
            this.candidateConstructorsCache.put(beanClass, candidateConstructors);
         }
      }
   }
   return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

看注释应该比较清晰了,大致总结一下:

  1. Spring会首先获取你声明的所有构造函数
  2. 然后会循环获取到的所有构造函数,判断有没加@Autowired注解,有加的会放到候选构造函数集合candidates里面去,默认@Autowired为true,check存在多个@Autowired为true的构造函数,有一个@Autowired为true的构造函数的构造函数就会设置为requiredConstructor,如果存在一个参数个数为0的构造函数(也只会有一个,就是无参构造函数),会设置为defaultConstructor
  3. 最后判断选择逻辑如下:
  • 如果candidates不为空,在再加上requiredConstructor为null且defaultConstructor不为null,则选用candidates+defaultConstructor,否则则选用candidates
  • 如果声明的只有一个构造函数,且参数个数大于0的,则直接选用返回
  • 如果有两个声明的构造函数,然后primaryConstructor和defaultConstructor都不为null且两个不相等,则两个都作为返回值
  • 如果只有primaryConstructor,且primaryConstructor不为null,则使用他
  • 啥都不满足就是没有即Spring会用他自己的默认的构造函数(其实就是无参构造)

给几个例子

例子一(只有无参):

@Component
public class IndexService {
   @Autowired
   OrderDao orderDao;
   public IndexService() {
   }
}

值得注意的是这种只有无参的,determineConstructorsFromBeanPostProcessors返回null

如果看懂了上面代码就很好理解,Spring为什么这么做呢?因为Spring认为你提供一个无参构造的,相当于没有提供构造函数,Spring会使用自己的无参构造,效果是一致的。

例子二(只有一个有参)

@Component
public class IndexService {
   @Autowired
   OrderDao orderDao;
   public IndexService(OrderDao orderDao) {
   }
}

也很好理解,在上面有一个if,如果只有一个有参那么会返回此构造

例子三(结合上面两个,既提供无参又提供有参)


看上面代码,如果提供了两个构造,但是又没加@Autowired,然后又不满足上面第3.3那个if,那么不会选用你提供的这两个,直接返回Null,因为Spring不知道你想选择哪一个

例子四(我们怎么返回多个构造函数让Spring去抉择选用)

其实就是这个方法determineConstructorsFromBeanPostProcessors,怎么返回一个数组
如果能完全看懂上面代码。那么要返回一个[]。就需要如下写了:

@Component
public class IndexService {
   @Autowired
   OrderDao orderDao;
   public IndexService() {
   }
   @Autowired(required = false)
   public IndexService(OrderDao orderDao) {
      this.orderDao = orderDao;
   }
   @Autowired(required = false)
   public IndexService(OrderDao orderDao, Luban luban) {
   }
}


其实也很好理解就是如果你要让Spring后面去判断哪个构造函数最适合,你得先用@Autowired来声明哪些个来参与判断,这里值得注意的是required 这个属性必须显示声明,否则默认为true,那就只能有一个构造被 @Autowired标注了,这里也只会返回一个,其实也就是上面的requiredConstructor
看完这些例子,就知道抛出问题的第二个肯定会return null了,不信的话大家可以尝试下,如果return null,那么Spring会利用反射调用无参构造进行Bean的初始化
好,有了多个构造,那么Spring怎么选择哪一个构造进行初始化呢,是选参数多的还是参数少的,或者说是public的呢?这个后面再说