你知道Spring怎么确定实例化对象的构造器吗?

2,406 阅读8分钟

你的赞是我最大的动力,期待与你共同进步

1.开篇

  上一篇文章学习了在Spring中如何通过工厂方法来实例化对象的,详细分析了createBeanInstance()方法中调用的instantiateUsingFactoryMethod() 方法,今天这个片文章,将来分析另一个被调用的方法 determineConstructorsFromBeanPostProcessors()。方法入口如下: 确定构造方法   在这个的实现中,我们又看到了非常熟悉的 BeanPostProcessors 的处理,代码如下:

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
        throws BeansException {

    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                if (ctors != null) {
                    return ctors;
                }
            }
        }
    }
    return null;
}

  从上述代码中,可以看到 Spring 中的处理方式就是先获取到所有的 BeanPostProcessors 的子类实现,然后循环判断,如果有符合条件的, 那么就调用该类的 determineCandidateConstructors() 方法,完成相应的处理。 实现类代用方法   在文章正式开始之前,又到了问问题的时候了, ibp.determineCandidateConstructors() 在执行 determineCandidateConstructors() 方法的 BeanPostProcessor 的实现类中,有一个 AutowiredAnnotationBeanPostProcessor, 我这里有一个问题,就是这个类是在什么时候放到 BeanDefinitionMap中的呢?请查看Spring容器初始化之先发五虎

2 你真的知道Spring如何选择构造器吗?

  文章开始之前,还是要从使用场景入手,然后在通过源码来分析,毕竟源码是不会骗人的。。。

2.1情形一
@Service
public class DemoServiceOne {

}
2.2情形二
@Service
public class DemoServiceOne {
    @Autowired
 DemoServiceTwo demoServiceTwo;

    public DemoServiceOne(){}

    public DemoServiceOne(DemoServiceTwo demoServiceTwo){
      this.demoServiceTwo = demoServiceTwo;
    }
}
2.3情形三
@Service
public class DemoServiceOne {

 @Autowired
 DemoServiceTwo demoServiceTwo;

 @Autowired
 DemoServiceThree demoServiceThree;

 public DemoServiceOne(DemoServiceTwo demoServiceTwo){
  this.demoServiceTwo = demoServiceTwo;
 }

 public DemoServiceOne(DemoServiceThree demoServiceThree, DemoServiceTwo demoServiceTwo){
  this.demoServiceTwo = demoServiceTwo;
  this.demoServiceThree = demoServiceThree;
 }
}
2.4情形四
@Service
public class DemoServiceOne {

 @Autowired
 DemoServiceTwo demoServiceTwo;

 @Autowired
 DemoServiceThree demoServiceThree;

 public DemoServiceOne(DemoServiceTwo demoServiceTwo){
  this.demoServiceTwo = demoServiceTwo;
 }
 @Autowired
 public DemoServiceOne(DemoServiceThree demoServiceThree, DemoServiceTwo demoServiceTwo){
  this.demoServiceTwo = demoServiceTwo;
  this.demoServiceThree = demoServiceThree;
 }
}

3 AutowiredAnnotationBeanPostProcessor 类中的方法

  从代码的实现可以看出,对于一个放在注册到容器中的 BeanName,都会做一次这个判断。至于没有交给Spring的类,这里当然是不会做处理了。

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

  // Let's check for lookup methods here...
  // 首先检查 lookup 方法
  if (!this.lookupMethodsChecked.contains(beanName)) {
   try {
    ReflectionUtils.doWithMethods(beanClass, method -> {
     Lookup lookup = method.getAnnotation(Lookup.class);
     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);
   }
   this.lookupMethodsChecked.add(beanName);
  }

  // Quick check on the concurrent map first, with minimal locking.
  // 从缓存中查找
  Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
  // 缓存中没有
  if (candidateConstructors == null) {
   // 同步代码块
   synchronized (this.candidateConstructorsCache) {
    candidateConstructors = this.candidateConstructorsCache.get(beanClass);
    if (candidateConstructors == null) {
     Constructor<?>[] rawCandidates;
     try {
      // 获取 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 大小为 前面获取到的类的构造参数个数
     List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
     //存放依赖注入的required=true的构造器
     Constructor<?> requiredConstructor = null;
     //存放默认构造器
     Constructor<?> defaultConstructor = null;
     //获取主要的构造器,大多数的情况下为 null
     Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
     int nonSyntheticConstructors = 0;
     for (Constructor<?> candidate : rawCandidates) {
      // 判断构造器是否为合成构造器,只要是我们自己申明的都不是合成构造器
      if (!candidate.isSynthetic()) {
       // 不是合成构造器,标记非合成构造器的数字 加一
       nonSyntheticConstructors++;
      }
      else if (primaryConstructor != null) {
       continue;
      }
      //查找当前构造器上的注解,有些构造器上面可能有注解,有些没有。这里要做区分
      AnnotationAttributes ann = findAutowiredAnnotation(candidate);
      if (ann == null) {
       // 没有注解
       // 获取创建 Bean使用的 class
       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) {
        //已经存在一个required=true的构造器了,抛出异常
        throw new BeanCreationException(beanName,
          "Invalid autowire-marked constructor: " + candidate +
          ". Found constructor with 'required' Autowired annotation already: " +
          requiredConstructor);
       }
       //判断此注解上的required属性 默认为 true 可设置为 false
       // 这里是用来处理两个注解一个 required 为 true,一个 为false的情况
       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);
        }
        //若为true
        //将当前构造器赋值给 requiredConstructor
        requiredConstructor = candidate;
       }
       // 当前的构造器添加到候选的构造器集合中
       candidates.add(candidate);
      }
      //如果该构造函数上没有注解,再判断构造函数上的参数个数是否为0
      else if (candidate.getParameterCount() == 0) {
       //如果没有参数,加入defaultConstructor集合,这里可以看出没有构造器的情况下,将无参构造器赋值给默认的构造器
       defaultConstructor = candidate;
      }
     }
     //适用的构造器集合若不为空
     if (!candidates.isEmpty()) {
      // Add default constructor to list of optional constructors, as fallback.
      //若没有required=true的构造器
      if (requiredConstructor == null) {
       if (defaultConstructor != null) {
        //将defaultConstructor集合的构造器加入适用构造器集合
        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]);
     }
     //如果适用的构造器集合为空,且Bean只有一个构造器并且此构造器参数数量大于0
     else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
      //就使用此构造器来初始化
      candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
     }
     //如果构造器有两个,且默认构造器不为空
     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 若不初始化 后面的判断会有问题
      candidateConstructors = new Constructor<?>[0];
     }
     //放入缓存,方便下一次调用,不需要上述的解析过程了,直接在缓存中获取
     this.candidateConstructorsCache.put(beanClass, candidateConstructors);
    }
   }
  }
  // 这里可以看到对 candidateConstructors 的初始化是有意义的
  return (candidateConstructors.length > 0 ? candidateConstructors : null);
 }

  首先来分析一下上述代码主要住了什么事,选取主要的步骤进行说明:

①:首先获取类的构造方法,记录在 Constructor<?>[] rawCandidates

rawCandidates = beanClass.getDeclaredConstructors();无参构造器也会被拿到。下图中,以类中没有构造器的情形举例

获取类的构造器 ②: for 循环 rawCandidates 对其中的每一个构造器进行判断

③:判断构造器上是否加了注解

  • 3.1 有加注解

    先判断requiredConstructor集合是否为空, 若不为空则代表之前已经有一个required=true的构造器了,两个true将抛出异常. 再判断candidates 集合是否为空,若不为空则表示之前已经有一个打了注解的构造器,若有required又是true,抛出异常. 若上述判断都通过了,将当前构造器赋值给 requiredConstructor集合中,再放入candidates集合中。

  • 3.2 没有加注解

    如果是无惨构造器则赋值给 defaultConstructor,其他的构造器不做处理,在会后返回的时候返回null

④:没有加注解且参数的个数为 0。将当前 for 循环的构造方法赋值给 defaultConstructor

 defaultConstructor = candidate;

⑤:确定构造器 确定构造器   这里确定构造器还是要结合前面的代码去看。

4 情形分析

  • 构造器上没有注解的情况:

    • 无参构造器将直接加入defaultConstructor集合中,无论是否申明。但是本方法最后返回的是 null。最终的实例化是通过默认的构造函数来完成的 instantiateBean(beanName, mbd)

    • 在构造器数量只有一个且有参数时,此唯一有参构造器将加入candidateConstructors集合中。最后返回。 有且仅有一个为被注解的有参构造器

    • 在构造器数量大于1个,无论是否申明无参构造器的情况下,将返回一个空的candidateConstructors集合,也就是没有找到构造器。

    不过这里需要区分一下是否声明无惨构造器: 如果未声明 defaultConstructor 为null 如果声明了 defaultConstructor 不为null

    多个构造器同时存且不包含注解
    多个构造器同时存且不包含注解

  综上所述,在构造器没有注解的情况下,如果有且仅有一个非无惨的构造器,那么本方法返回的就是这个构造器。如果大于一个或则只有一个 无参构造器,那么该方法返回的都是 null

  • 构造器上有注解的情况:

  构造器上有注解的情况需要判断required属性:

  • 两个构造器上都有 @Autowired 且 required属性都为true 抛出异常

    throw new BeanCreationException(beanName, "Invalid autowire-marked constructor: " + candidate + ". Found constructor with 'required' Autowired annotation already: " + requiredConstructor);

  • 两个构造器上都有 @Autowired 一个 required属性都为true 另一个 required属性都为false 抛出异常

    throw new BeanCreationException(beanName, "Invalid autowire-marked constructors: " + candidates + ". Found constructor with 'required' Autowired annotation: " + candidate);

  • 两个构造器上都有 @Autowired 且 required属性都为false 则正常通过,后面的方法会确定使用哪一个

5 总结

    1. 对象中存在多个未被注解的构造器determineCandidateConstructors()方法都会返回null这里有彩蛋,后面文章会提到
    1. 对象中有且仅有一个未被注入的构造器

      • 若该构造器为无参的,那么determineCandidateConstructors()返回 null
      • 若该构造构器为有参的,那么determineCandidateConstructors()返回 该构造器
    1. 仅有一个注入的构造器,则使用该构造器
    1. 有两个注入的构造器
      • required 都为 true 抛出异常
      • required 一个为 true 另一个为 false 抛出异常
      • required 都为 false 正常通过

  这篇文章中对Spring中通过使用 BeanPostProcessor 的实现类来完成构造器的确认进行了分析。当我们实例化一个对象的时候,构造方法确定了, 那么就可以通过使用构造方法来实例化了。但是,通过上面的分析发现,可能会有多个构造方法存在的情况,那么在这种情况下,Spring是如何确定使用哪个构造方法的, 也就是大名鼎鼎的推断构造器,下一篇文章中,将进行分析。

本文使用 mdnice 排版