Spring - 推断构造方法【3】

331 阅读4分钟

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

【3】推断构造方法

在上面的代码中我们进入这里的条件是:

  • 没有缓存 也就是说,如果我们是第一次进入这个方法的时候,此时是没有缓存的,那么就必须想想:如何构造我们的实例了。

  • 根据这里trace的代码能看出来,依赖的是BP的回调,这里的BeanPostProcessors属于是前面提前写进来的:


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

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

而这个监听事件,在原生的Spring中只在AutowiredAnnotationBeanPostProcessor中被重写了(对,就是依赖注入中处理Autowired的那个BP),因此我们来看看对应的代码:

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

  //.................

   // 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 {
                //取不到缓存,那么就直接从class对象里取所有的构造方法
               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);
             //这里记录required的构造方法(一个类只能有一个,所以这里只用对象,而不是数组)
            Constructor<?> requiredConstructor = null;
            Constructor<?> defaultConstructor = null;
             //和kotlin有关的变量
            Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
             //和kotlin有关的变量
            int nonSyntheticConstructors = 0;
            for (Constructor<?> candidate : rawCandidates) {
               if (!candidate.isSynthetic()) {
                  nonSyntheticConstructors++;
               }
               else if (primaryConstructor != null) {
                  continue;
               }
                //构造方法是否有@Autowired注解
               MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
                //没有autowired注解
               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) {
                   //并且之前解析到了一个autowired(required=true)的构造方法,那么抛出异常
                  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为true的
                     if (!candidates.isEmpty()) {
                        throw new BeanCreationException(beanName,
                              "Invalid autowire-marked constructors: " + candidates +
                              ". Found constructor with 'required' Autowired annotation: " +
                              candidate);
                     }
                     requiredConstructor = candidate;
                  }
                  candidates.add(candidate);
               }
                // 没有autowired的注解,并且找到了是无参的构造方法
               else if (candidate.getParameterCount() == 0) {
                  defaultConstructor = candidate;
               }
            }
             //不是空的:这些都是加了autowired的构造方法
            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]);
            }
             //没有添加了autowired的构造方法,且只有一个构造方法,且是有参的:正常返回
            else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
               candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
            }
             //以下和kotlin有关
            else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                  defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
               //..........
      }
   }
   return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

总结

在这三篇的内容中,我们详细地介绍了Spring是如何推断构造方法,并创建对应实例的。

由于Spring是一个用于生产环境的IOC容器(框架),其实可以看到很多地方都使用到了缓存,这里也不例外,可以说在规模较大的环境中,缓存是一个相当常见的一个解决方案,可以节省多次调用下的时间。

那么,针对我们的流程,就可以补充上IOC中缺失的那些部分:如何创建一个实例

总的来说,这部分的内容处于Bean生命周期中靠前的位置,毕竟我们bean生命周期总是从构建一个实例后,才能对这些东西进行进一步的初始化(包括:代理、属性注入等)。

这部分内容和之前的循环依赖也有部分关系,在Spring最新的版本中已不推荐使用非构造方法的属性注入(这大概是因为非构造方法的属性注入,违背了开闭原则,使得类变得不够稳定),但如果是构造方法造成的循环依赖问题,那么这个问题相对来说就是无解的了,毕竟如果只有构造方法可以注入属性,那么在需要实例注入的前提下,我们是没办法创建出对应的实例的,更别提解决循环依赖问题了。

流程图已更新:processon.com/diagraming/…