在上篇文章BeanDefinition解析流程-注解配置中我们讲解了@Import注解标注的类会被Spring当前lite类型的配置类进行解析,在ConfigurationClassParser类中有一个processImports()方法上一节我们没讲,这一节我们就详细分析一下它。

首先看一下这一个方法:

// ConfigurationClassParser.java
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

getImports()

在上面的processImports()方法的参数中,有一个参数调用了getImports()方法,我们来看一下这个方法:

// ConfigurationClassParser.java
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
  // 注意这里定义了两个Set集合,一个是记录导入的类,一个记录已经处理过的类
  // 之所以定义已经处理过的类,是为了避免循环Import的问题,导致陷入死循环
  Set<SourceClass> imports = new LinkedHashSet<>();
  Set<SourceClass> visited = new LinkedHashSet<>();
  // 收集@Imports注解中的value值
  collectImports(sourceClass, imports, visited);
  return imports;
}

private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
  throws IOException {
  // 因为visited是一个Set集合,所以如果该sourceClass已经存在,调用add方法就会返回false,说明之前已经处理过该sourceClass
  // 直接跳过该sourceClass的处理
  if (visited.add(sourceClass)) {
    // 循环该配置了上的所有注解
    for (SourceClass annotation : sourceClass.getAnnotations()) {
      String annName = annotation.getMetadata().getClassName();
      // 如果注解不是@Import,递归调用collectImports()方法,这里为什么要递归调用呢?
      // 因为其它注解上可能也标注了@Import注解,所以要递归处理到所有能找到的@Import注解
      // 例如Spring系列想用的@EnableXXX注解,都是在@EnableXXX注解上标注@Import注解实现的
      if (!annName.equals(Import.class.getName())) {
        collectImports(annotation, imports, visited);
      }
    }
    // 将该配置类上标注的@Import注解的value值添加到imports集合中
    imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
  }
}

processImports()

该方法主要是处理配置类通过@Import注解导入的类。

public @interface Import {
  Class<?>[] value();
}

通过@Import注解的定义我们可以看到,@Import的注解的value是class数组,也就是其可以通过在注解上配置class类型导入多个类。而且通过下面的处理逻辑我们分析出来,@Import注解导入的类分为四种情况分别处理:

  • ImportSelector类型处理

    如果导入的类实现了ImportSelector接口,在处理该类的时候会直接回调该类的selectImports()方法

  • DeferredImportSelector类型处理

    该接口是ImportSelector接口的子类,它有了分组group的概念,但是其与ImportSelector最大的不同在于,实现了该接口的类会比实现了ImportSelector接口的类延迟处理,等配置类都解析完才会处理该接口的导入类。

  • ImportBeanDefinitionRegistrar类型处理

    如果导入类实现了ImportBeanDefinitionRegistrar接口,在这里会将该类添加到configClass中,在后续loadBeanDefinitions()时会调用该类的registerBeanDefinitions()方法

  • 普通Bean类型处理

    如果导入类没有实现上述几个接口,Spring就会将其当做一个普通配置类,调用processConfigurationClass()走上一篇文章BeanDefinition解析流程-注解配置配置类的解析流程

//  ConfigurationClassParser.java
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                            Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
                            boolean checkForCircularImports) {

  if (importCandidates.isEmpty()) {
    return;
  }

  if (checkForCircularImports && isChainedImportOnStack(configClass)) {
    this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
  }
  else {
    this.importStack.push(configClass);
    try {
      for (SourceClass candidate : importCandidates) {
        // 导入的类实现了ImportSelector接口
        if (candidate.isAssignable(ImportSelector.class)) {
          // 加载并实例化该类
          Class<?> candidateClass = candidate.loadClass();
          ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                                                         this.environment, this.resourceLoader, this.registry);
          Predicate<String> selectorFilter = selector.getExclusionFilter();
          if (selectorFilter != null) {
            exclusionFilter = exclusionFilter.or(selectorFilter);
          }
          // 如果实现的是DeferredImportSelector接口,通过deferredImportSelectorHandler进行处理,这里只是将其
          // 放入了一个延迟执行的集合,等待后续延迟处理
          if (selector instanceof DeferredImportSelector) {
            this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
          }
          else {
            // 实现ImportSelector接口直接调用selectImports()方法
            String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
            Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
            // 递归调用processImports方法,处理导入类上的@Import注解
            processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
          }
        }
        // 实现了ImportBeanDefinitionRegistrar接口,直接将该类添加到configClass的importBeanDefinitionRegistrar
        // 字段中,等到后续处理
        else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
          Class<?> candidateClass = candidate.loadClass();
          ImportBeanDefinitionRegistrar registrar =
            ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                                 this.environment, this.resourceLoader, this.registry);
          configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
        }
        else {
          // 如果是普通配置Bean,将以被导入类名为key,导入类注解原信息为value注册到importStack
          // 这里的importStack也就是上一节我们讲的为了适配ImportAware接口注册那个单例Bean
          // 具体位置为:Spring系列-BeanDefinition解析流程-注解配置的processConfigBeanDefinitions()下的121行代码
          this.importStack.registerImport(
            currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
          // 然后以该类作为配置类,递归调用processConfigurationClass()走处理配置类逻辑
          processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
        }
      }
    }
    catch (BeanDefinitionStoreException ex) {
      throw ex;
    }
    catch (Throwable ex) {
      throw new BeanDefinitionStoreException(
        "Failed to process import candidates for configuration class [" +
        configClass.getMetadata().getClassName() + "]", ex);
    }
    finally {
      this.importStack.pop();
    }
  }
}

其中我们需要主要介绍下实现了DeferredImportSelector接口的导入类的处理方式,其它的要么我们已经介绍过,要么很简单就不解释了。

DeferredImportSelectorHandler

实现了DeferredImportSelector接口的导入类,会交给DeferredImportSelectorHandler类去处理。

private class DeferredImportSelectorHandler {

  @Nullable
  private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

  public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
    DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
    // 我们看到上面deferredImportSelectors已经赋予一个空集合了,为什么这里还要判断空呢?
    // 这就需要看下面的process()方法,在处理的时候,将deferredImportSelectors又置为null了。
    // 而process()方法是在配置类都处理完成后,最后调用的处理deferredImportSelector类型,在处理的过程中,会将
    // deferredImportSelectors置为空,如果此时又有需要处理的deferredImportSelector,那么立即分组处理
    if (this.deferredImportSelectors == null) {
      // 可以看到,在这种情况下只注册了一个holder,所以此时分组的意义不是太大了
      DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
      handler.register(holder);
      handler.processGroupImports();
    }
    else {
      // 如上所示,正常来说第一次进来的时候,deferredImportSelectors不为null,是一个实例化号的集合,这里仅仅只是做了
      // 一个简单的add将该deferredImportSelector包装后的DeferredImportSelectorHolder添加到集合中,然后等待延迟处理
      this.deferredImportSelectors.add(holder);
    }
  }
  
  // 延迟处理执行逻辑,当所有的配置类都处理完成后,就会调用process方法,处理延迟import方法
  // 这一步是在所有候选配置类执行完parse()方法后调用的
  // 在ConfigurationClassParser.parse(Set<BeanDefinitionHolder> configCandidates)这个重载方法中
  public void process() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    // 这里将deferredImportSelectors置为null了,所以说,process执行期间,就不能在往该处理集合中添加延迟处理类了
    // 该次处理完成后,会将deferredImportSelectors集合重置
    this.deferredImportSelectors = null;
    try {
      if (deferredImports != null) {
        // 创建延迟处理分组处理器,里面封装了分组逻辑以及分组处理逻辑
        DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
        // 对deferredImports进行排序,延迟导入类可以通过实现Order接口或使用@Order注解排序
        deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
        // 将延迟导入类分组注册
        deferredImports.forEach(handler::register);
        // 分组处理延迟导入类
        handler.processGroupImports();
      }
    }
    finally {
      // 执行完后,重置deferredImportSelectors集合
      this.deferredImportSelectors = new ArrayList<>();
    }
  }
}

DeferredImportSelectorGroupingHandler

private class DeferredImportSelectorGroupingHandler {
  
  // 用于保存deferredImportSelector分组结果,每一个value都是一个组
  private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
  // 保存配置类的注解元数据对象和配置类的映射关系
  // 这里的配置类指的是导入DeferredImportSelector实现类的配置类
  private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();

  // 将deferredImportSelector分组注册
  public void register(DeferredImportSelectorHolder deferredImport) {
    // 获取该deferredImportSelector的组
    // getImportGroup()是DeferredImportSelector的一个接口,我们可以通过该接口返回组实现类类型
    Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
    // computeIfAbsent如果key不存在则添加,如果存在则返回对应的value
    // 如果组实现类不为null,则用组实现类作为分组key,如果实现类为null,则用当前DeferredImportSelectorHolder对象作为key
    // 如果组实现类都为null,则相当于不分组
    // 如果组实现类已存在,则返回该组对应的DeferredImportSelectorGrouping对象,该对象中保存了改组所有的
    // deferredImportSelector, 如果不存在,则创建一个默认组,组的默认实现类为DefaultDeferredImportSelectorGroup
    // 通过DefaultDeferredImportSelectorGroup可以获取到该组下所有deferredImportSelector导入的类
    DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
      (group != null ? group : deferredImport),
      key -> new DeferredImportSelectorGrouping(createGroup(group)));
    // 将该deferredImportSelector加入改组,上一行代码相当于创建一个组
    grouping.add(deferredImport);
    // 将配置类注解元数据对象和配置类放入集合中暂存,方便下面获取
    this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                                  deferredImport.getConfigurationClass());
  }
  
  // 处理分组导入
  public void processGroupImports() {
    // 循环每一个组
    for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
      Predicate<String> exclusionFilter = grouping.getCandidateFilter();
      // 获取该组导入的所有类并循环处理
      grouping.getImports().forEach(entry -> {
        // 这里用了上一步存放起来的配置类的数据,只需要需要configurationClass是因为下面processImports()方法需要
        ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
        try {
          // 对导入的类再次处理@Import,处理级联导入的问题(即导入的类又导入了其它的类)
          processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
                         Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
                         exclusionFilter, false);
        }
        catch (BeanDefinitionStoreException ex) {
          throw ex;
        }
        catch (Throwable ex) {
          throw new BeanDefinitionStoreException(
            "Failed to process import candidates for configuration class [" +
            configurationClass.getMetadata().getClassName() + "]", ex);
        }
      });
    }
  }
  // 创建分组
  private Group createGroup(@Nullable Class<? extends Group> type) {
    // 如果分组类为null,默认使用DefaultDeferredImportSelectorGroup.class
    Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class);
    // 实例化组对象,可以看到这里传入到环境变量对象等一些参数
    return ParserStrategyUtils.instantiateClass(effectiveType, Group.class,
                                                ConfigurationClassParser.this.environment,
                                                ConfigurationClassParser.this.resourceLoader,
                                                ConfigurationClassParser.this.registry);
  }
}

DeferredImportSelectorGrouping

private static class DeferredImportSelectorGrouping {
  // 组对象
  private final DeferredImportSelector.Group group;
  // 该组对应的所有deferredImportSelector
  private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();

  DeferredImportSelectorGrouping(Group group) {
    this.group = group;
  }

  public void add(DeferredImportSelectorHolder deferredImport) {
    this.deferredImports.add(deferredImport);
  }

  public Iterable<Group.Entry> getImports() {
    // 循环处理所有的deferredImportSelector
    for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
      // 这一步会将该deferredImportSelector导入的类全部放到imports集合中
      // imports集合是DefaultDeferredImportSelectorGroup默认分组实现类中的一个字段
      this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                         deferredImport.getImportSelector());
    }
    // 返回该组中的imports集合
    return this.group.selectImports();
  }
  // 这是过滤器
  public Predicate<String> getCandidateFilter() {
    Predicate<String> mergedFilter = DEFAULT_EXCLUSION_FILTER;
    for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
      Predicate<String> selectorFilter = deferredImport.getImportSelector().getExclusionFilter();
      if (selectorFilter != null) {
        mergedFilter = mergedFilter.or(selectorFilter);
      }
    }
    return mergedFilter;
  }
}

DefaultDeferredImportSelectorGroup

private static class DefaultDeferredImportSelectorGroup implements Group {
  // 存放该组所有deferredImportSelector导入的类信息
  private final List<Entry> imports = new ArrayList<>();

  @Override
  public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
    // 处理该组所有deferredImportSelector,将导入的类信息封装为Entry添加到imports集合
    for (String importClassName : selector.selectImports(metadata)) {
      this.imports.add(new Entry(metadata, importClassName));
    }
  }

  // 拿到上面process()处理后导入的所有类信息
  @Override
  public Iterable<Entry> selectImports() {
    return this.imports;
  }
}

ParserStrategyUtils

// ParserStrategyUtils.java
static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo, Environment environment,
                              ResourceLoader resourceLoader, BeanDefinitionRegistry registry) {

  Assert.notNull(clazz, "Class must not be null");
  Assert.isAssignable(assignableTo, clazz);
  if (clazz.isInterface()) {
    throw new BeanInstantiationException(clazz, "Specified class is an interface");
  }
  ClassLoader classLoader = (registry instanceof ConfigurableBeanFactory ?
                             ((ConfigurableBeanFactory) registry).getBeanClassLoader() : resourceLoader.getClassLoader());
  // 实例化
  T instance = (T) createInstance(clazz, environment, resourceLoader, registry, classLoader);
  // 如果实现了aware接口,执行适配器接口
  // 为什么要在这里执行适配器接口,在bean的初始化流程中不是会执行实现了适配器接口的方法吗?
  // 因为这里还是在获取BeanDefinititon的阶段中,还没走到初始化单例Bean的流程,所以这里的实例化对实现了aware接口
  // 的类进行了适配
  ParserStrategyUtils.invokeAwareMethods(instance, environment, resourceLoader, registry, classLoader);
  return instance;
}
// ParserStrategyUtils.java
private static void invokeAwareMethods(Object parserStrategyBean, Environment environment,
                                       ResourceLoader resourceLoader, BeanDefinitionRegistry registry, @Nullable ClassLoader classLoader) {

  if (parserStrategyBean instanceof Aware) {
    if (parserStrategyBean instanceof BeanClassLoaderAware && classLoader != null) {
      ((BeanClassLoaderAware) parserStrategyBean).setBeanClassLoader(classLoader);
    }
    if (parserStrategyBean instanceof BeanFactoryAware && registry instanceof BeanFactory) {
      ((BeanFactoryAware) parserStrategyBean).setBeanFactory((BeanFactory) registry);
    }
    if (parserStrategyBean instanceof EnvironmentAware) {
      ((EnvironmentAware) parserStrategyBean).setEnvironment(environment);
    }
    if (parserStrategyBean instanceof ResourceLoaderAware) {
      ((ResourceLoaderAware) parserStrategyBean).setResourceLoader(resourceLoader);
    }
  }
}

至此,Import导入的逻辑就梳理完了。

ImportAware

接下来我们扩展一下有关Import的功能,ImportAware接口的实现原理。

public interface ImportAware extends Aware {

  // 设置导入类的注解元数据,也就是能获取到导入了实现该接口的类的注解元数据 
  void setImportMetadata(AnnotationMetadata importMetadata);
}

举个例子:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

  boolean proxyTargetClass() default false;

  boolean exposeProxy() default false;
}

EnableAspectJAutoProxy注解上使用@Import导入了AspectJAutoProxyRegistrar类,当我们在某一个配置类上标注了@EnableAspectJAutoProxy注解后,Spring会将AspectJAutoProxyRegistrar导入,我们怎么才能在AspectJAutoProxyRegistrar类中获取到@EnableAspectJAutoProxy注解中的proxyTargetClass这些信息呢?

实际上如果AspectJAutoProxyRegistrar实现了ImportSelector接口,那么在调用selectImport()接口时,就会将@EnableAspectJAutoProxy注解元数据信息当做参数传入。

public interface ImportSelector {

  // 这里传入的importingClassMetadata实际上就是@EnableAspectJAutoProxy的注解元信息
  String[] selectImports(AnnotationMetadata importingClassMetadata);

  @Nullable
  default Predicate<String> getExclusionFilter() {
    return null;
  }

}

但是如果AspectJAutoProxyRegistrar类没有实现ImportSelector接口呢?

这时候就需要ImportAware接口出场了,ImportAware就是为了解决这个问题而存在的。

前面处理Import的时候我们说过了在processImports()方法中有这么一行代码:

// 将被导入类和导入类注解元信息保存到importStack中
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());

上一篇文章BeanDefinition解析流程-注解配置中我们也强调了一行代码:

// 这就是将上面的importStack对象注册成一个单例Bean
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());

如果导入类实现了ImportAware接口,那么在初始化该类的时候,会被ImportAwareBeanPostProcessor后置处理器处理:

private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

  private final BeanFactory beanFactory;

  public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
  }

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) {
    // 处理实现了ImportAware接口的类
    if (bean instanceof ImportAware) {
      // 这里获取到的就是我们上面注册的importStack单例Bean
      ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
      // 通过该类名获取到对应导入类的注解元信息
      AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
      if (importingClass != null) {
        // 调用setImportMetadata()方法传入
        ((ImportAware) bean).setImportMetadata(importingClass);
      }
    }
    return bean;
  }
}

综上,就是ImportAware的作用已经实现原理。