Spring Configuration - @Import

"从@Import浅入Spring配置加载"

Posted by tablesheep on August 7, 2021

从@Import浅入Spring配置加载

version:Spring Framework 5.3.x

AbstractApplicationContext

invokeBeanFactoryPostProcessors

通过refresh()加载完BeanFactoryPostProcessor后,调用此方法进行BeanFactoryPostProcessor处理,使用PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors进行

PostProcessorRegistrationDelegate

invokeBeanFactoryPostProcessors

1
2
public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors)
  1. 使用传入的所有BeanFactoryPostProcessor进行处理(BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
  2. 获取beanFactory中的所有BeanDefinitionRegistryPostProcessor
  3. 处理PriorityOrdered级别的BeanDefinitionRegistryPostProcessorConfigurationClassPostProcessor
  4. 处理Ordered级别的BeanDefinitionRegistryPostProcessor
  5. 处理普通的BeanDefinitionRegistryPostProcessor

ConfigurationClass

配置类封装,包含了配置类的各种信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
final class ConfigurationClass {
//配置类源信息
   private final AnnotationMetadata metadata;

   private final Resource resource;

   @Nullable
   private String beanName;
//由谁引入
   private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
//@Bean装载
   private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();

   private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
         new LinkedHashMap<>();
//ImportBeanDefinitionRegistrar信息
   private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
         new LinkedHashMap<>();

   final Set<String> skippedBeanMethods = new HashSet<>();
    ......
}

ConfigurationClassPostProcessor

逻辑集中在processConfigBeanDefinitions方法中,主要使用ConfigurationClassParser解析配置,使用BeanDefinitionReader将解析到的BeanDefinition注册到BeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
      PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
......

   /**
    * Derive further bean definitions from the configuration classes in the registry.
    */
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
      int registryId = System.identityHashCode(registry);
      if (this.registriesPostProcessed.contains(registryId)) {
         throw new IllegalStateException(
               "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
      }
      if (this.factoriesPostProcessed.contains(registryId)) {
         throw new IllegalStateException(
               "postProcessBeanFactory already called on this post-processor against " + registry);
      }
      this.registriesPostProcessed.add(registryId);

      processConfigBeanDefinitions(registry);
   }

......

   /**
    * Build and validate a configuration model based on the registry of
    * {@link Configuration} classes.
    */
   public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
      ......

          //创建ConfigurationClassParser解析配置,使用BeanDefinitionReader将解析到的BeanDefinition注册到registry(DefaultListableBeanFactory)中
      // Parse each @Configuration class
      ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);

      Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
      Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
      do {
         StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
         parser.parse(candidates);
         parser.validate();

          //获取parser中processConfigurationClasses解析出的所有配置类
         Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
         configClasses.removeAll(alreadyParsed);

         // Read the model and create bean definitions based on its content
         if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                  registry, this.sourceExtractor, this.resourceLoader, this.environment,
                  this.importBeanNameGenerator, parser.getImportRegistry());
         }
          //使用BeanDefinitionReader装载所有配置类配置(BeanDefinition)
         this.reader.loadBeanDefinitions(configClasses);
         ......
      }
      while (!candidates.isEmpty());

......
   }

   ......

}

ConfigurationClassParser

存在大量递归调用,主要是为了处理配置中嵌入配置的情况,比如配置类中的@Bean方法、@Import引入新的配置类等。

processConfigurationClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
......

   // Recursively process the configuration class and its superclass hierarchy.
   SourceClass sourceClass = asSourceClass(configClass, filter);
   do {
       //调用doProcessConfigurationClass方法解析所有可能的配置情况
      sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
   }
   while (sourceClass != null);

    //将configClass放入map中,在ConfigurationClassPostProcessor中会获取所有的配置类进行导入(包括@Import 导入的普通类,ImportSelector导入的类)
   this.configurationClasses.put(configClass, configClass);
}

doProcessConfigurationClass

处理配置类,包括@Component@PropertySources@ComponentScans@Import@ImportResource@Bean

1
2
3
4
5
6
7
8
9
10
11
protected final SourceClass doProcessConfigurationClass(
      ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
      throws IOException {

   ......

       //处理 @Import配置
   // Process any @Import annotations
   processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
    ......
}

collectImports

getImports调用它,使用递归收集@Import注解信息(比如@Enable*注解中的@Import,而@Enable*在启动类上)

1
2
3
4
5
6
7
8
9
10
11
12
13
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
      throws IOException {

   if (visited.add(sourceClass)) {
      for (SourceClass annotation : sourceClass.getAnnotations()) {
         String annName = annotation.getMetadata().getClassName();
         if (!annName.equals(Import.class.getName())) {
            collectImports(annotation, imports, visited);
         }
      }
      imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
   }
}

processImports

对收集到的@Import注解信息进行处理,引入的普通配置类会封装成ConfigurationClassImportSelector引入的类会转换成普通类最后封装成ConfigurationClass,最后会在processConfigurationClass中放入ConfigurationClassParser的变量中保存;而ImportBeanDefinitionRegistrar则会放入ConfigurationClass中,最后都会在ConfigurationClassBeanDefinitionReader进行BeanDefinition注册。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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) {
            if (candidate.isAssignable(ImportSelector.class)) {
                //处理ImportSelector
               // Candidate class is an ImportSelector -> delegate to it to determine imports
               Class<?> candidateClass = candidate.loadClass();
                //创建ImportSelector对象,并回调BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, and ResourceLoaderAware 接口
               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);
               }
               if (selector instanceof DeferredImportSelector) {
                  this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
               }
               else {
                   //调用selectImports方法获取需要导入的类名,并封装成SourceClass集合
                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                  Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                   //递归调用处理selectImports获取到的类
                  processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
               }
            }
            else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                //处理ImportBeanDefinitionRegistrar
               // Candidate class is an ImportBeanDefinitionRegistrar ->
               // delegate to it to register additional bean definitions
               Class<?> candidateClass = candidate.loadClass();
                //创建ImportBeanDefinitionRegistrar对象,并回调BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, and ResourceLoaderAware 接口
               ImportBeanDefinitionRegistrar registrar =
                     ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                           this.environment, this.resourceLoader, this.registry);
                //将ImportBeanDefinitionRegistrar对象添加到ConfigurationClass中,后面统一通过ImportBeanDefinitionRegistrar将BeanDefinition注册导容器中
               configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
            }
            else {
               // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
               // process it as an @Configuration class
               this.importStack.registerImport(
                     currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                //将普通类封装成ConfigurationClass回调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();
      }
   }
}

ConfigurationClassBeanDefinitionReader

loadBeanDefinitionsForConfigurationClass

根据ConfigurationClass装载所有的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void loadBeanDefinitionsForConfigurationClass(
      ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

   if (trackedConditionEvaluator.shouldSkip(configClass)) {
      String beanName = configClass.getBeanName();
      if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
         this.registry.removeBeanDefinition(beanName);
      }
      this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
      return;
   }

   if (configClass.isImported()) {
       //普通配置类处理
      registerBeanDefinitionForImportedConfigurationClass(configClass);
   }
   for (BeanMethod beanMethod : configClass.getBeanMethods()) {
       //@Bean方法处理
      loadBeanDefinitionsForBeanMethod(beanMethod);
   }

    //文件资源处理
   loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    //ImportBeanDefinitionRegistrar处理
   loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}