【SpringBoot源码分析】Bean的加载过程

转自:https://www.cnblogs.com/lukama/p/14604894.html

 

-- 以下内容均基于2.1.8.RELEASE版本

在《SpringBoot启动过程的分析》系列文章中简要的对SpringBoot整体的启动流程作了梳理,但并未针对诸多细节进行分析。前面的篇章中介绍了从SpringBoot应用程序入口开始执行,一直到上下文刷新完成。期间它加载了所有的类,但是并未直接指出它是在哪个环节加载的类,在加载的过程中如何处理的,以及我们在程序入口所使用的各种注解是如何解析的。本文将对这一疑惑进行解答。

要分析SpringBoot加载类的过程,就必须清晰的知道我们的类到底在哪个环节被加载的。也就是需要定位到加载类的入口,如何来确定这个入口呢?通过阅读spring-framework的官方文档可以得知我们可以从ApplicationContext中来通过getBean()方法来获取Bean。那么通过这个入口就能找到存放Bean的地方,找到存放Bean的地方就可以通过调试得知它在什么时候被加载进来,进而确定Bean加载的入口。

找到Bean存放位置

这里通过一个简单示例来展示如何寻找Bean存放位置

1 public static void main(String[] args) {
2     SpringApplication application = new SpringApplication(Example.class);
3     ConfigurableApplicationContext context = application.run(args);
4     // 从容器中获取一个Bean
5     Example2 example2 = context.getBean(Example2.class);
6  
7 }

上述代码是一个非常常见的获取Bean的代码,跟踪context.getBean()方法就能找到它存放的位置。

 1 // AbstractApplicationContext.class
 2 public <T> T getBean(Class<T> requiredType) throws BeansException {
 3     assertBeanFactoryActive();
 4     // 从BeanFactory获取Bean
 5     return getBeanFactory().getBean(requiredType);
 6 }
 7  
 8 // DefaultListableBeanFactory.class
 9 public <T> T getBean(Class<T> requiredType) throws BeansException {
10     return getBean(requiredType, (Object[]) null);
11 }
12  
13 public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
14     Assert.notNull(requiredType, "Required type must not be null");
15     // 可以看到Object对象是这里获取的
16     Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
17     if (resolved == null) {
18         throw new NoSuchBeanDefinitionException(requiredType);
19     }
20     return (T) resolved;
21 }
22  
23 // ...中间省略部分代码
24  
25 private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
26     List<String> result = new ArrayList<>();
27  
28     // ① Check all bean definitions.
29     for (String beanName : this.beanDefinitionNames) {
30         // ...中间省略部分代码
31     }
32     return StringUtils.toStringArray(result);
33 }

① - 一路跟踪下来,可以看到所有的Bean都是在BeanFactory的beanDefinitionNames里面存放。因此关注这个属性何时被赋值就可以找到Bean加载的入口。

确定Bean在哪个环节被加载

当得知Bean存放于BeanFactory的beanDefinitionNames属性中,在启动阶段关注这个属性值的变化即可确定它在哪个阶段被赋值,可以肯定的是,它一定是在上下文容器创建完毕之后才会加载,因为容器都没有怎么存放。下图就展示了在创建完毕之后的上下文中Bean的初始化数量。

图: 创建完毕上下文容器

图中所展示的几个Bean是SpringBoot内置的处理器,在SpringBoot启动过程的分析-创建应用程序上下文一文中已经介绍过此处不再次解读。在创建完毕上下文之后有两个重要操作:预处理上下文、刷新上下文。那么初始化类必然就在这两个步骤中间了。首先在刷新上下文处打断点,看看在预处理上下文时是否初始化了其他的Bean。

图:预处理上下文完毕

 

查看刷新方法,它明显的调用了AbstractApplicationContext.refresh()。

 1 // SpringApplication.class
 2  
 3 private void refreshContext(ConfigurableApplicationContext context) {
 4     refresh(context);
 5     if (this.registerShutdownHook) {
 6         try {
 7             context.registerShutdownHook();
 8         }
 9         catch (AccessControlException ex) {
10             // Not allowed in some environments.
11         }
12     }
13 }
14  
15 protected void refresh(ApplicationContext applicationContext) {
16     Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
17     ((AbstractApplicationContext) applicationContext).refresh();
18 }

此处可以发现它多了一个"Example"的类,单并未出现其他新的类,Example类是笔者调试程序的入口,在前面文章中也已经介绍过。因此可以断定,其他的类肯定在刷新上下文容器的时候被加载。快速确定方法就是在刷新上下文容器下方打断点,查看beanDefinitionNames的内容变化。在确定了是刷新容器时加载所有类之后,进入刷新容器的代码,可以看到它也清晰的划分了多个步骤,和上面一样,以每个方法为界,观察bean的加载情况。

在refresh()方法中,通过调式可以得知它在invokeBeanFactoryPostProcessors()方法会加载所有的Bean

 1 public void refresh() throws BeansException, IllegalStateException {
 2     synchronized (this.startupShutdownMonitor) {
 3     
 4         // Prepare this context for refreshing.
 5         prepareRefresh();
 6  
 7         // Tell the subclass to refresh the internal bean factory.
 8         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 9  
10         // Prepare the bean factory for use in this context.
11         prepareBeanFactory(beanFactory);
12  
13         try {
14             // Allows post-processing of the bean factory in context subclasses.
15             postProcessBeanFactory(beanFactory);
16  
17             // Invoke factory processors registered as beans in the context.
18             invokeBeanFactoryPostProcessors(beanFactory);
19  
20             // Register bean processors that intercept bean creation.
21             registerBeanPostProcessors(beanFactory);
22  
23             // Initialize message source for this context.
24             initMessageSource();
25  
26             // Initialize event multicaster for this context.
27             initApplicationEventMulticaster();
28  
29             // Initialize other special beans in specific context subclasses.
30             onRefresh();
31  
32             // Check for listener beans and register them.
33             registerListeners();
34  
35             // Instantiate all remaining (non-lazy-init) singletons.
36             finishBeanFactoryInitialization(beanFactory);
37  
38             // Last step: publish corresponding event.
39             finishRefresh();
40         }
41         //...省略部分代码
42     }
43 }

通过BeanFactoryPostProcessor加载所有的类

提示:

下文中所提到的BeanFactoryPostProcessor,均表示类型为BeanFactoryPostProcessor的接口统称,包括了它的扩展接口BeanDefinitionRegistryPostProcessor以及他们的实现类。

invokeBeanFactoryPostProcessors()方法是加载并调用所有的BeanFactoryProcessor,我们在前面的文章中已经详细介绍了它的执行流程和业务细节,不明白的同学可以再去回顾一下SpringBoot启动过程的分析-刷新ApplicationContext。这里再重申一下有关于BeanFactoryPostProcessor的相关概念。加强了这些概念,后续对其他代码的理解也会更容易。

BeanFactoryPostProcessor,是Spring内部诸多PostProcessor中的一种,它是一个接口。注意它的前缀名称为BeanFactory,Bean工厂意味着它可以创建Bean,根据它的注释描述可以得知它可以修改Bean的定义,也可以修改Bean的属性值,但是它只能用于处理BeanDefinition,而不能处理Bean的实例。简单说就是,它可以在类实例化之前去修改它。另外一个BeanDefinitionRegistryPostProcessor它继承了BeanFactoryPostProcessor,对其进行了扩展,主要用于修改上下文中的Bean定义,加载所有常规的Bean,添加Bean。简单点理解就是它要比BeanFactoryPostProcessor更先执行。主要用于注册Bean。

在调用AbstractApplicationContext.invokeBeanFactoryPostProcessors()方法的时候需要注意它传入的BeanFactoryPostProcessor参数,具体可以看代码:

 1 // AbstractApplicationContext.java
 2  
 3 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
 4     //
 5     PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
 6  
 7     // ...省略部分代码
 8 }
 9  
10 public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
11     return this.beanFactoryPostProcessors;
12 }

① - 这里需要注意传入的参数,它由getBeanFactoryPostProcessors()方法提供,而这个方法返回的是AbstractApplicationContext.beanFactoryPostProcessor这个属性值。这个属性内部所定义的BeanFactoryPostProcessor都是在ApplicationContextInitializer的扩展中添加进来的,而创建上下文容器时添加的内部的处理器则存放在DefaultListableBeanFactory.beanDefinitionNames这个属性中。所以在处理BeanFactoryPostProcessor的时候首先处理的是ApplicationContextInitializer中的内容。也就意味着通过ApplicationContextInitializer添加的BeanFactoryPostProcessor将会优先执行

通过两处不同的BeanFactoryPostProcessor可以反推出BeanFactoryPostProcessor初始化的两种方式:

  1. 通过ConfigurableApplicationContext.addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor)来添加
  2. 通过BeanDefinitionRegistry.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)来注册一个Bean

本文的重点是分析Bean加载,此处对于BeanFactoryPostProcessor的植入涉及到另外一个课题:Spring框架的扩展点。对扩展点的分析此处先占位,有兴趣可以查看SpringFramework的扩展点

实际上对于Bean加载不光包括我们自己编写的业务代码,也包括SpringBoot自己的其他组件。因为BeanFactoryPostProcessor本身也是一个类。他们在ApplicationContextInitializer接口中被添加,或是在BeanDefinitionRegistry中被注册。区别就是一个是直接添加实例,一个是注册BeanDefinition。言归正传回到Bean的加载中来;此处对于通过ApplicationContextInitializer接口中被添加的BeanFactoryPostProcessor不作分析,因为代码比较简洁,他们本身也没涉及过多的操作,感兴趣的可以自己debug。这里重点分析通过BeanDefinitionRegistry注册的BeanFactoryPostProcessor即DefaultListableBeanFactory.beanDefinitionNames这个属性中注册的类。内置的BeanFactoryPostProcessor是在容器创建的时候加入的,可参考之前的分析注册内定的BeanFactoryPostProcessor

org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.context.event.DefaultEventListenerFactory
org.springframework.context.event.EventListenerMethodProcessor
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

经过查看这些内置的类,只有ConfigurationClassPostProcessor和类加载相关。

小结

  前面章节部分通过一种简要(笨拙)的方式来定位到我们需要分析的代码点,在**容器刷新阶段**中的**invokeBeanFactoryPostProcessors()**方法中由调用BeanFactoryPostProcessor接口开始,执行了具有配置解析、BeanDefinition加载的实现类。通过对BeanFactoryPostProcessor接口的实现进行分析结合源码执行流程
  得知它的执行顺序。这一点尤其重要,它是后面整个流程的入口。

ConfigurationClassPostProcessor

主要用于对@Configuration注解进行处理。在SpringBoot应用中,往往都是从一个Main函数开始,启动类上面也必须使用@SpringBootApplication注解来标明它的身份;因此@Configuration注解也代表着应用的起点;因在BeanFactoryPostProcessor被调用的时候是按照优先级来的,首先被调用的是BeanDefinitionRegistryPostProcessor,所以首先执行postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法。

 1 // ConfigurationClassPostProcessor.java
 2  
 3 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
 4     //
 5     int registryId = System.identityHashCode(registry);
 6     if (this.registriesPostProcessed.contains(registryId)) {
 7         throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
 8     }
 9     //
10     if (this.factoriesPostProcessed.contains(registryId)) {
11         throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
12     }
13     //
14     this.registriesPostProcessed.add(registryId);
15     //
16     processConfigBeanDefinitions(registry);
17 }

① - 获取注册ID
② - 判断当前Processor是否被执行过
③ - 添加到已处理列表
④ - 处理配置相关的BeanDefinition

  1 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  2  
  3     List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
  4     // 获取所有已注册的BeanDefinition,寻找具有@Configuration注解的类
  5     String[] candidateNames = registry.getBeanDefinitionNames();
  6     
  7     // 遍历所有的beanName
  8     for (String beanName : candidateNames) {
  9         // 根据名称找到BeanDefinition
 10         BeanDefinition beanDef = registry.getBeanDefinition(beanName);
 11         // 判断当前类是Full模式还是Lite模式,就为了打印个日志?No,查看日志内容,打印的是:当前类已经被当做一个configuration类被处理过。
 12         // 那就意味着默认情况下它是没有设置ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE 这个属性的。
 13         if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
 14             if (logger.isDebugEnabled()) {
 15                 logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
 16             }
 17         }
 18         // 判断当前处理的类是不是完整的配置类,也就是是否被@Configuration注解修饰,若被修饰则会给当前的BeanDefinition设置一个attribute(org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass = full)
 19         else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
 20             // 加入配置候选列表
 21             configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
 22         }
 23     }
 24  
 25     // 若没有被@Configuration注解的类,直接返回
 26     // Return immediately if no @Configuration classes were found
 27     if (configCandidates.isEmpty()) {
 28         return;
 29     }
 30  
 31     // 根据优先级排序
 32     // Sort by previously determined @Order value, if applicable
 33     configCandidates.sort((bd1, bd2) -> {
 34         int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
 35         int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
 36         return Integer.compare(i1, i2);
 37     });
 38  
 39     // 设置BeanNameGenerator用于生成稍后检测到的Bean的名称
 40     // Detect any custom bean name generation strategy supplied through the enclosing application context
 41     SingletonBeanRegistry sbr = null;
 42     if (registry instanceof SingletonBeanRegistry) {
 43         sbr = (SingletonBeanRegistry) registry;
 44         if (!this.localBeanNameGeneratorSet) {
 45             BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
 46             if (generator != null) {
 47                 this.componentScanBeanNameGenerator = generator;
 48                 this.importBeanNameGenerator = generator;
 49             }
 50         }
 51     }
 52  
 53     if (this.environment == null) {
 54         this.environment = new StandardEnvironment();
 55     }
 56  
 57     // 新建一个配置类解析器,用于解析所有@Configuration注解的类
 58     // Parse each @Configuration class
 59     ConfigurationClassParser parser = new ConfigurationClassParser(
 60             this.metadataReaderFactory, this.problemReporter, this.environment,
 61             this.resourceLoader, this.componentScanBeanNameGenerator, registry);
 62  
 63     // 将要被解析的配置类
 64     Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
 65     // 已经被解析的配置类
 66     Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 67     do {
 68         // ① 开始解析配置类
 69         parser.parse(candidates);
 70         parser.validate();
 71  
 72         // ② 获取解析到的配置类
 73         Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
 74         configClasses.removeAll(alreadyParsed);
 75  
 76         // ③ 构建Reader对象,为加载Bean做准备 Read the model and create bean definitions based on its content
 77         if (this.reader == null) {
 78             this.reader = new ConfigurationClassBeanDefinitionReader(
 79                     registry, this.sourceExtractor, this.resourceLoader, this.environment,
 80                     this.importBeanNameGenerator, parser.getImportRegistry());
 81         }
 82         
 83         // ④ 从配置类开始加载Bean
 84         this.reader.loadBeanDefinitions(configClasses);
 85         alreadyParsed.addAll(configClasses);
 86  
 87         candidates.clear();
 88         if (registry.getBeanDefinitionCount() > candidateNames.length) {
 89             String[] newCandidateNames = registry.getBeanDefinitionNames();
 90             Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
 91             Set<String> alreadyParsedClasses = new HashSet<>();
 92             for (ConfigurationClass configurationClass : alreadyParsed) {
 93                 alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
 94             }
 95             for (String candidateName : newCandidateNames) {
 96                 if (!oldCandidateNames.contains(candidateName)) {
 97                     BeanDefinition bd = registry.getBeanDefinition(candidateName);
 98                     if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
 99                             !alreadyParsedClasses.contains(bd.getBeanClassName())) {
100                         candidates.add(new BeanDefinitionHolder(bd, candidateName));
101                     }
102                 }
103             }
104             candidateNames = newCandidateNames;
105         }
106     }
107     while (!candidates.isEmpty());
108  
109     // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
110     if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
111         sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
112     }
113  
114     if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
115         // Clear cache in externally provided MetadataReaderFactory; this is a no-op
116         // for a shared cache since it'll be cleared by the ApplicationContext.
117         ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
118     }
119 }

根据上面的void processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法中的do-while循环可以看到,它内部是按照解析@Configuration->取出@Configuration->构建BeanDefinitionReader->从@Configuration读取BeanDefinition的流程来完成类的加载。

开始解析@Configuration类

@Configuration注解是Spring中基于Java配置容器中的一个注解,属于类级别的注解,它主要用于标明一组@Bean定义的来源。通常@Configuration和@Bean同时使用。

  1 // ConfigurationClassParser.java
  2  
  3 public void parse(Set<BeanDefinitionHolder> configCandidates) {
  4     // 遍历所有具有@Configuration注解的类
  5     for (BeanDefinitionHolder holder : configCandidates) {
  6         BeanDefinition bd = holder.getBeanDefinition();
  7         try {
  8             if (bd instanceof AnnotatedBeanDefinition) {
  9                 // 解析AnnotatedBeanDefinition类型的配置类(可以获取类的注解元数据)
 10                 parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
 11             }
 12             else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
 13                 parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
 14             }
 15             else {
 16                 parse(bd.getBeanClassName(), holder.getBeanName());
 17             }
 18         }
 19         catch (BeanDefinitionStoreException ex) {
 20             throw ex;
 21         }
 22         catch (Throwable ex) {
 23             throw new BeanDefinitionStoreException(
 24                     "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
 25         }
 26     }
 27  
 28     this.deferredImportSelectorHandler.process();
 29 }
 30  
 31 // 包装为ConfigurationClass对象
 32 protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
 33     processConfigurationClass(new ConfigurationClass(metadata, beanName));
 34 }
 35  
 36 // 判断是否已经执行过
 37 protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
 38     if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
 39         return;
 40     }
 41  
 42     ConfigurationClass existingClass = this.configurationClasses.get(configClass);
 43     if (existingClass != null) {
 44         if (configClass.isImported()) {
 45             if (existingClass.isImported()) {
 46                 existingClass.mergeImportedBy(configClass);
 47             }
 48             // Otherwise ignore new imported config class; existing non-imported class overrides it.
 49             return;
 50         }
 51         else {
 52             // Explicit bean definition found, probably replacing an import.
 53             // Let's remove the old one and go with the new one.
 54             this.configurationClasses.remove(configClass);
 55             this.knownSuperclasses.values().removeIf(configClass::equals);
 56         }
 57     }
 58  
 59     // 包装为SourceClass便于统一处理
 60     // Recursively process the configuration class and its superclass hierarchy.
 61     SourceClass sourceClass = asSourceClass(configClass);
 62     do {
 63         // 这里才开始处理配置类
 64         sourceClass = doProcessConfigurationClass(configClass, sourceClass);
 65     }
 66     while (sourceClass != null);
 67  
 68     this.configurationClasses.put(configClass, configClass);
 69 }
 70  
 71 // 真正开始处理配置的方法
 72 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
 73         throws IOException {
 74  
 75     // 优先处理@Component注解
 76     if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
 77         // 递归处理
 78         // Recursively process any member (nested) classes first
 79         processMemberClasses(configClass, sourceClass);
 80     }
 81  
 82     // 处理@PropertySource注解
 83     // Process any @PropertySource annotations
 84     for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
 85             sourceClass.getMetadata(), PropertySources.class,
 86             org.springframework.context.annotation.PropertySource.class)) {
 87         if (this.environment instanceof ConfigurableEnvironment) {
 88             processPropertySource(propertySource);
 89         }
 90         else {
 91             logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
 92                     "]. Reason: Environment must implement ConfigurableEnvironment");
 93         }
 94     }
 95  
 96     // 处理@ComponentScan注解
 97     // Process any @ComponentScan annotations
 98     Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
 99             sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
100     if (!componentScans.isEmpty() &&
101             !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
102         for (AnnotationAttributes componentScan : componentScans) {
103             // The config class is annotated with @ComponentScan -> perform the scan immediately
104             Set<BeanDefinitionHolder> scannedBeanDefinitions =
105                     this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
106             // Check the set of scanned definitions for any further config classes and parse recursively if needed
107             for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
108                 BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
109                 if (bdCand == null) {
110                     bdCand = holder.getBeanDefinition();
111                 }
112                 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
113                     parse(bdCand.getBeanClassName(), holder.getBeanName());
114                 }
115             }
116         }
117     }
118  
119     // 处理@Import注解
120     // Process any @Import annotations
121     processImports(configClass, sourceClass, getImports(sourceClass), true);
122  
123     // 处理@ImportResource注解
124     // Process any @ImportResource annotations
125     AnnotationAttributes importResource =
126             AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
127     if (importResource != null) {
128         String[] resources = importResource.getStringArray("locations");
129         Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
130         for (String resource : resources) {
131             String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
132             configClass.addImportedResource(resolvedResource, readerClass);
133         }
134     }
135  
136     // 处理单个@Bean方法
137     // Process individual @Bean methods
138     Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
139     for (MethodMetadata methodMetadata : beanMethods) {
140         configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
141     }
142  
143     // 处理接口默认方法
144     // Process default methods on interfaces
145     processInterfaces(configClass, sourceClass);
146  
147     // 处理父类的方法
148     // Process superclass, if any
149     if (sourceClass.getMetadata().hasSuperClass()) {
150         String superclass = sourceClass.getMetadata().getSuperClassName();
151         if (superclass != null && !superclass.startsWith("java") &&
152                 !this.knownSuperclasses.containsKey(superclass)) {
153             this.knownSuperclasses.put(superclass, configClass);
154             // Superclass found, return its annotation metadata and recurse
155             return sourceClass.getSuperClass();
156         }
157     }
158  
159     // No superclass -> processing is complete
160     return null;
161 }

@Configuration配置类同时也和其他注解有关联,这里说的关联是其他注解的行为会影响配置类本身的状态。例如方法中提到的@Component、@ComponentScan、@PropertySource、@Import、@Bean、@ImportResource。

处理@Component注解

@Component注解表示被修饰的类将会被识别为受Spring管理的类。将会被注册到Bean容器中。

 1 private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
 2     // 获取成员类
 3     Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
 4     if (!memberClasses.isEmpty()) {
 5         List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
 6         for (SourceClass memberClass : memberClasses) {
 7             // 判断是否有@Configuration或者@Component注解
 8             if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getC
 9             lassName().equals(configClass.getMetadata().getClassName())) {
10                 candidates.add(memberClass);
11             }
12         }
13         // 排序
14         OrderComparator.sort(candidates);
15         // 检测是否有循环导入(@Import)的问题
16         for (SourceClass candidate : candidates) {
17             if (this.importStack.contains(configClass)) {
18                 this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
19             }
20             else {
21                 this.importStack.push(configClass);
22                 try {
23                     // 递归调用处理
24                     processConfigurationClass(candidate.asConfigClass(configClass));
25                 }
26                 finally {
27                     this.importStack.pop();
28                 }
29             }
30         }
31     }
32 }

在该方法中,主要用于处理当前传入的configClass内部的嵌套类、成员类中是否有@Configuration、@Component注解。一般来说@Configuratio
n都是单独使用的一个类。

处理@PropertySource注解

@PropertySource注解用于加载指定的properties配置文件到Spring的Environment中

 1 // 内部实现比较简单,自行debug即可
 2 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
 3     // 判断当前环境对象是否是可配置的
 4     if (this.environment instanceof ConfigurableEnvironment) {
 5         processPropertySource(propertySource);
 6     }
 7     else {
 8         logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
 9     }
10 }
处理@ComponentScan注解

@ComponentScan注解用于指明当前应用将扫描哪些包下的具有@Component注解的类。这个注解必须添加到@Configuration类中

 1 // 根据ComponentScans配置的包路径查找带@Component注解的类
 2 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
 3 if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
 4     // 获取所有带@Component注解的类
 5     for (AnnotationAttributes componentScan : componentScans) {
 6         // The config class is annotated with @ComponentScan -> perform the scan immediately
 7         Set<BeanDefinitionHolder> scannedBeanDefinitions =
 8                 this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
 9         // Check the set of scanned definitions for any further config classes and parse recursively if needed
10         for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
11             BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
12             if (bdCand == null) {
13                 bdCand = holder.getBeanDefinition();
14             }
15             if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
16                 parse(bdCand.getBeanClassName(), holder.getBeanName());
17             }
18         }
19     }
20 }

这里重点分析它是如何查找@ComponentScans注解的,跳过无用的调用链,查看真正开始查找的方法。

 1 // AnnotationConfigUtils.java
 2 // 需要注意的是参数:metadata代表从哪里获取,containerClassName表示包含注解(例如@ComponentScans,它本身的值可以包含多个@ComponentScan),annotationClassName是当前要获取的目标注解也就是@ComponentScan
 3 static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata, String containerClassName, String annotationClassName) {
 4  
 5     Set<AnnotationAttributes> result = new LinkedHashSet<>();
 6  
 7     // 8     // Direct annotation present?
 9     addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));
10  
11     //12     // Container annotation present?
13     Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
14     if (container != null && container.containsKey("value")) {
15         for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) {
16             addAttributesIfNotNull(result, containedAttributes);
17         }
18     }
19  
20     // Return merged result
21     return Collections.unmodifiableSet(result);
22 }

提示:
在这个方法内部分了两个操作,第一个是直接获取@ComponentScan这个注解,第二个是获取@ComponentScans注解。这两者是有区别的。

① - 此处为@ComponentScan,称之为直接注解”,即在类上面直接声明的注解。

  1 // StandardAnnotationMetadata.class
  2 public Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
  3     return (this.annotations.length > 0 ? AnnotatedElementUtils.getMergedAnnotationAttributes(getIntrospectedClass(), annotationName, classValuesAsString, this.nestedAnnotationsAsMap) : null);
  4 }
  5  
  6 // AnnotatedElementUtils.class
  7 public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
  8         String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
  9  
 10     AnnotationAttributes attributes = searchWithGetSemantics(element, null, annotationName, new MergedAnnotationAttributesProcessor(classValuesAsString, nestedAnnotationsAsMap));
 11     AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap);
 12     return attributes;
 13 }
 14  
 15 // 通过一系列的重载方法,最终调用此方法
 16 private static <T> T searchWithGetSemantics(AnnotatedElement element,
 17         Set<Class<? extends Annotation>> annotationTypes, @Nullable String annotationName,
 18         @Nullable Class<? extends Annotation> containerType, Processor<T> processor,
 19         Set<AnnotatedElement> visited, int metaDepth) {
 20  
 21     if (visited.add(element)) {
 22         try {
 23             // Start searching within locally declared annotations
 24             // 获取当前元素声明的所有注解
 25             List<Annotation> declaredAnnotations = Arrays.asList(AnnotationUtils.getDeclaredAnnotations(element));
 26             // 获取这些注解中指定的类型
 27             T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations, annotationTypes, annotationName, containerType, processor, visited, metaDepth);
 28             if (result != null) {
 29                 return result;
 30             }
 31  
 32             if (element instanceof Class) {  // otherwise getAnnotations doesn't return anything new
 33                 Class<?> superclass = ((Class<?>) element).getSuperclass();
 34                 if (superclass != null && superclass != Object.class) {
 35                     List<Annotation> inheritedAnnotations = new LinkedList<>();
 36                     for (Annotation annotation : element.getAnnotations()) {
 37                         if (!declaredAnnotations.contains(annotation)) {
 38                             inheritedAnnotations.add(annotation);
 39                         }
 40                     }
 41                     // Continue searching within inherited annotations
 42                     result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations,
 43                             annotationTypes, annotationName, containerType, processor, visited, metaDepth);
 44                     if (result != null) {
 45                         return result;
 46                     }
 47                 }
 48             }
 49         }
 50         catch (Throwable ex) {
 51             AnnotationUtils.handleIntrospectionFailure(element, ex);
 52         }
 53     }
 54  
 55     return null;
 56 }
 57  
 58 private static <T> T searchWithGetSemanticsInAnnotations(@Nullable AnnotatedElement element,
 59             List<Annotation> annotations, Set<Class<? extends Annotation>> annotationTypes,
 60             @Nullable String annotationName, @Nullable Class<? extends Annotation> containerType,
 61             Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
 62  
 63     // 遍历所有注解
 64     // Search in annotations
 65     for (Annotation annotation : annotations) {
 66         // 获取当前注解类型
 67         Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
 68         if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
 69             // 判断是否处理过、当前注解的名称是否和将要查找的一致、是否默认处理(默认为true,请debug的时候注意传入的参数)
 70             if (annotationTypes.contains(currentAnnotationType) || currentAnnotationType.getName().equals(annotationName) || processor.alwaysProcesses()) {
 71                 // 若匹配,则查找内部的注解属性
 72                 T result = processor.process(element, annotation, metaDepth);
 73                 if (result != null) {
 74                     if (processor.aggregates() && metaDepth == 0) {
 75                         processor.getAggregatedResults().add(result);
 76                     }
 77                     else {
 78                         return result;
 79                     }
 80                 }
 81             }
 82             // 如果没有找到
 83             // Repeatable annotations in container?
 84             else if (currentAnnotationType == containerType) {
 85                 for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
 86                     T result = processor.process(element, contained, metaDepth);
 87                     if (result != null) {
 88                         // No need to post-process since repeatable annotations within a
 89                         // container cannot be composed annotations.
 90                         processor.getAggregatedResults().add(result);
 91                     }
 92                 }
 93             }
 94         }
 95     }
 96  
 97     // Recursively search in meta-annotations
 98     for (Annotation annotation : annotations) {
 99         Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
100         if (!AnnotationUtils.hasPlainJavaAnnotationsOnly(currentAnnotationType)) {
101             T result = searchWithGetSemantics(currentAnnotationType, annotationTypes, annotationName, containerType, processor, visited, metaDepth + 1);
102             if (result != null) {
103                 processor.postProcess(element, annotation, result);
104                 if (processor.aggregates() && metaDepth == 0) {
105                     processor.getAggregatedResults().add(result);
106                 }
107                 else {
108                     return result;
109                 }
110             }
111         }
112     }
113  
114     return null;
115 }
116  
117 // AnnotatedElementUtils.class内部类AnnotatedElementUtils.class
118 public AnnotationAttributes process(@Nullable AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
119     return AnnotationUtils.retrieveAnnotationAttributes(annotatedElement, annotation, this.classValuesAsString, this.nestedAnnotationsAsMap);
120 }
121  
122 // AnnotationUtils.class
123 static AnnotationAttributes retrieveAnnotationAttributes(@Nullable Object annotatedElement,
124         Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
125  
126     Class<? extends Annotation> annotationType = annotation.annotationType();
127     AnnotationAttributes attributes = new AnnotationAttributes(annotationType);
128  
129     // 遍历注解的方法,获取属性名称和属性值,填充至AnnotationAttributes对象内部(实际上就是个Map)
130     for (Method method : getAttributeMethods(annotationType)) {
131         try {
132             Object attributeValue = method.invoke(annotation);
133             Object defaultValue = method.getDefaultValue();
134             if (defaultValue != null && ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
135                 attributeValue = new DefaultValueHolder(defaultValue);
136             }
137             attributes.put(method.getName(), adaptValue(annotatedElement, attributeValue, classValuesAsString, nestedAnnotationsAsMap));
138         }
139         catch (Throwable ex) {
140             if (ex instanceof InvocationTargetException) {
141                 Throwable targetException = ((InvocationTargetException) ex).getTargetException();
142                 rethrowAnnotationConfigurationException(targetException);
143             }
144             throw new IllegalStateException("Could not obtain annotation attribute value for " + method, ex);
145         }
146     }
147  
148     return attributes;
149 }

② - 此处为@ComponentScans,称之为”容器注解”,它可以包含多个@ComponentScan,代码逻辑和获取直接注解@ComponentScan并没有太大差异,可自行debug

看到这里可以得出一个结论:有3种使用注解定义包扫描路径的方法

  1. @SpringBootApplication(scanBasePackages = "com.example")
  2. @ComponentScan(value = {"com.example"})
  3. @ComponentScans({@ComponentScan("com.abcd"), @ComponentScan("com.efgh")})
    注意:其中1和2是可以同时存在,1和3可以同时存在,2和3不可以同时存在
    1、2同时存在只取2的值
    1、3同时存在取1、3的值

处理到这一步,仅仅是获取到了所有的@ComponentScan注解,接下来还需要解析注解里面配置的包路径

  1 // ConfigurationClassParser.class 284行
  2 for (AnnotationAttributes componentScan : componentScans) {
  3     // 解析当前注解配置的包路径下的类
  4     // The config class is annotated with @ComponentScan -> perform the scan immediately
  5     Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
  6     // 检查返回的BeanDefinition里面是否有其他的配置类,如果需要的话会递归进行解析
  7     // Check the set of scanned definitions for any further config classes and parse recursively if needed
  8     for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
  9         BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
 10         if (bdCand == null) {
 11             bdCand = holder.getBeanDefinition();
 12         }
 13         // 若是配置类,执行配置类的解析操作
 14         if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
 15             parse(bdCand.getBeanClassName(), holder.getBeanName());
 16         }
 17     }
 18 }
 19  
 20 // 以下代码为获取BeanDefinition的具体流程
 21 // ComponentScanAnnotationParser.class
 22 public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
 23     
 24     // 构建扫描器
 25     ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
 26  
 27     // 构建类名生成器
 28     Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
 29     boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
 30     scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator : BeanUtils.instantiateClass(generatorClass));
 31  
 32     // 获取类的作用域模型
 33     ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
 34     if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
 35         scanner.setScopedProxyMode(scopedProxyMode);
 36     }
 37     else {
 38         Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
 39         scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
 40     }
 41  
 42     // 获取资源模式(注解配置扫描包都是扫描class因此此处为:**/*.class)
 43     scanner.setResourcePattern(componentScan.getString("resourcePattern"));
 44  
 45     // 获取@ComponentScan注解里面配置的include过滤器
 46     for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
 47         for (TypeFilter typeFilter : typeFiltersFor(filter)) {
 48             scanner.addIncludeFilter(typeFilter);
 49         }
 50     }
 51     // 获取@ComponentScan注解里面配置的exclude过滤器
 52     for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
 53         for (TypeFilter typeFilter : typeFiltersFor(filter)) {
 54             scanner.addExcludeFilter(typeFilter);
 55         }
 56     }
 57  
 58     //  获取@ComponentScan注解里面配置的lazyInit值
 59     boolean lazyInit = componentScan.getBoolean("lazyInit");
 60     if (lazyInit) {
 61         scanner.getBeanDefinitionDefaults().setLazyInit(true);
 62     }
 63  
 64     // 获取需要扫描的路径集合
 65     Set<String> basePackages = new LinkedHashSet<>();
 66     String[] basePackagesArray = componentScan.getStringArray("basePackages");
 67     for (String pkg : basePackagesArray) {
 68         String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
 69         Collections.addAll(basePackages, tokenized);
 70     }
 71     for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
 72         basePackages.add(ClassUtils.getPackageName(clazz));
 73     }
 74     if (basePackages.isEmpty()) {
 75         basePackages.add(ClassUtils.getPackageName(declaringClass));
 76     }
 77  
 78     scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
 79         @Override
 80         protected boolean matchClassName(String className) {
 81             return declaringClass.equals(className);
 82         }
 83     });
 84     // 通过扫描器扫描指定路径下的具有@Component注解的类
 85     return scanner.doScan(StringUtils.toStringArray(basePackages));
 86 }
 87  
 88 // ClassPathBeanDefinitionScanner.class
 89  
 90 protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
 91     Assert.notEmpty(basePackages, "At least one base package must be specified");
 92     Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
 93     for (String basePackage : basePackages) {
 94         // 查找所有@Component注解标识的类
 95         Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
 96         for (BeanDefinition candidate : candidates) {
 97             // 获取作用域元数据
 98             ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
 99             candidate.setScope(scopeMetadata.getScopeName());
100             // 生成类名
101             String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
102             // 对普通的Bean 进行处理
103             if (candidate instanceof AbstractBeanDefinition) {
104                 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
105             }
106             // 对包含有注解的Bean进行处理,比如@Lazy、@Primary
107             if (candidate instanceof AnnotatedBeanDefinition) {
108                 AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
109             }
110             // 检查当前加载的Bean名称是否有冲突
111             if (checkCandidate(beanName, candidate)) {
112                 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
113                 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
114                 beanDefinitions.add(definitionHolder);
115                 registerBeanDefinition(definitionHolder, this.registry);
116             }
117         }
118     }
119     return beanDefinitions;
120 }
121  
122 // ClassPathScanningCandidateComponentProvider.class
123  
124 public Set<BeanDefinition> findCandidateComponents(String basePackage) {
125     if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
126         return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
127     }
128     else {
129         // 真正开始搜索类的方法
130         return scanCandidateComponents(basePackage);
131     }
132 }
133  
134 private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
135         Set<BeanDefinition> candidates = new LinkedHashSet<>();
136         try {
137             // 获取资源的路径
138             String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern;
139             // 获取所有资源
140             Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
141             boolean traceEnabled = logger.isTraceEnabled();
142             boolean debugEnabled = logger.isDebugEnabled();
143             // 为每一个类生成BeanDefinition对象
144             for (Resource resource : resources) {
145                 if (traceEnabled) {
146                     logger.trace("Scanning " + resource);
147                 }
148                 if (resource.isReadable()) {
149                     try {
150                         MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
151                         // 判断是否具有@Component注解
152                         if (isCandidateComponent(metadataReader)) {
153                             ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
154                             sbd.setResource(resource);
155                             sbd.setSource(resource);
156                             if (isCandidateComponent(sbd)) {
157                                 if (debugEnabled) {
158                                     logger.debug("Identified candidate component class: " + resource);
159                                 }
160                                 candidates.add(sbd);
161                             }
162                             else {
163                                 if (debugEnabled) {
164                                     logger.debug("Ignored because not a concrete top-level class: " + resource);
165                                 }
166                             }
167                         }
168                         else {
169                             if (traceEnabled) {
170                                 logger.trace("Ignored because not matching any filter: " + resource);
171                             }
172                         }
173                     }
174                     catch (Throwable ex) {
175                         throw new BeanDefinitionStoreException(
176                                 "Failed to read candidate component class: " + resource, ex);
177                     }
178                 }
179                 else {
180                     if (traceEnabled) {
181                         logger.trace("Ignored because not readable: " + resource);
182                     }
183                 }
184             }
185         }
186         catch (IOException ex) {
187             throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
188         }
189         return candidates;
190     }

至此,通过@ComponentScan注解配置扫描指定的包,到获取到具体的带有@Component注解的类已经全部获取完毕。

处理@Import注解

@Import注解主要用于引入另外一个@Configuration。和Spring XML配置文件中的标签功能一样。

  1 // ConfigurationClassParser.class 302行
  2 // 处理@Import注解,请注意参数内部的getImports方法
  3 processImports(configClass, sourceClass, getImports(sourceClass), true);
  4  
  5 private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
  6     Set<SourceClass> imports = new LinkedHashSet<>();
  7     Set<SourceClass> visited = new LinkedHashSet<>();
  8     collectImports(sourceClass, imports, visited);
  9     return imports;
 10 }
 11  
 12 // 递归获取@Import注解
 13 private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException {
 14     // 添加已处理的避免无限递归
 15     if (visited.add(sourceClass)) {
 16         // 获取传入资源上的注解列表
 17         for (SourceClass annotation : sourceClass.getAnnotations()) {
 18             // 获取注解名称
 19             String annName = annotation.getMetadata().getClassName();
 20             // 若当前注解不是@Import则递归查找
 21             if (!annName.equals(Import.class.getName())) {
 22                 collectImports(annotation, imports, visited);
 23             }
 24         }
 25         // 添加已经获取的所有注解
 26         imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
 27     }
 28 }
 29  
 30  
 31 private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
 32  
 33     if (importCandidates.isEmpty()) {
 34         return;
 35     }
 36  
 37     if (checkForCircularImports && isChainedImportOnStack(configClass)) {
 38         this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
 39     }
 40     else {
 41         this.importStack.push(configClass);
 42         try {
 43             for (SourceClass candidate : importCandidates) {
 44                 // 是否是ImportSelector的实现
 45                 if (candidate.isAssignable(ImportSelector.class)) {
 46                     // 获取SourceClass对象中所代表的真正对象,存储于SourceClass.source属性中
 47                     // Candidate class is an ImportSelector -> delegate to it to determine imports
 48                     Class<?> candidateClass = candidate.loadClass();
 49                     // 获取ImportSelector实例
 50                     ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
 51                     // 调用Aware接口
 52                     ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
 53                     //
 54                     if (selector instanceof DeferredImportSelector) {
 55                         // 1.1
 56                         this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
 57                     } else {
 58                         // 获取导入的类名称数组
 59                         String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
 60                         // 将其转换为SourceClass, 目的是为了下一步的递归获取
 61                         Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
 62                         // 递归调用
 63                         processImports(configClass, currentSourceClass, importSourceClasses, false);
 64                         //
 65                     }
 66                 }
 67                 //
 68                 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
 69                     // Candidate class is an ImportBeanDefinitionRegistrar ->
 70                     // delegate to it to register additional bean definitions
 71                     // 获取SourceClass对象中所代表的真正对象,存储于SourceClass.source属性中
 72                     Class<?> candidateClass = candidate.loadClass();
 73                     // 获取ImportBeanDefinitionRegistrar实例
 74                     ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
 75                     // 调用Aware接口
 76                     ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
 77                     // 将其存放于configClass的importBeanDefinitionRegistrars属性中
 78                     configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
 79                     // 3.1
 80                 }
 81                 // 都不是的话把它当做@Configuration来处理
 82                 else {
 83                     // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
 84                     // process it as an @Configuration class
 85                     this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
 86                     // 将其作为@Configuration处理
 87                     processConfigurationClass(candidate.asConfigClass(configClass));
 88                 }
 89             }
 90         }
 91         catch (BeanDefinitionStoreException ex) {
 92             throw ex;
 93         }
 94         catch (Throwable ex) {
 95             throw new BeanDefinitionStoreException(
 96                     "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex);
 97         }
 98         finally {
 99             this.importStack.pop();
100         }
101     }
102 }

提示:
ImporSelector主要用于导入@Configuration配置类,并且可以实现EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口,并在调用ImportSelector.selectImports方法之前调用它们。
ImportBeanDefinitionRegistrar主要用于导入导入@Configuration配置,并可以注册BeanDefinition

① - 是否是DeferredImportSelector, 它将会在所有的@Configuration执行完毕之后才执行。
1.1 将其放入DeferredImportSelectorHandler对象的deferredImportSelectors属性中,在当前方法内部直至执行完毕都未见这些DeferredImportSelector被执行,它是在哪里被执行的呢?向上翻到"开始解析@Configuration类"章节,查看parse()方法的最后一行,它是在所有的解析操作完成之后被执行。

② - 这里并未执行任何操作,仅仅是继续递归,因为当前条件分支处理的是ImportSelector,它的作用就是导入配置,因此继续递归查看是否有内嵌的其他配置,最终将会把配置类缓存,在解析完毕之后一并处理。

③ - 是否是ImportBeanDefinitionRegistrar的实现
3.1 此处并未执行获取的selector,仅仅是将其存放于当前解析的配置对象(ConfigClass)的importBeanDefinitionRegistrars属性中,那么它在哪里被执行呢?因其具有注册BeanDefinition的功能,所以此处并未处理,和DeferredImportSelector一样,此处也是先解析出来,等到该执行的时候再执行。
当前处理逻辑处于parse()方法中,对解析结果的调用在parse()方法的后面,因此可以查阅@Configuration读取BeanDefinition章节。

对于@Import的解析可以做一个简要的总结:

它用于导入配置类,配置类又分为可以延迟加载的、可以注册BeanDefinition的,无一例外他们都是在@Configuration类获取完毕之后才会被执行。需要注意的是解析配置类的对象是ConfigurationClassParser,它内部缓存了当前解析但并未被执行的类。在其执行完毕所有的解析动作之后会依次调用DeferredImportSelector和ImportBeanDefinitionRegistrar。

处理@ImportResource注解

用于引入Spring xml配置文件,类似于Spring XML中的标签,默认使用XmlBeanDefinitionReader来解析XML中的标签。
例如:

 1 @Configuration
 2 @ImportResource("classpath:/com/acme/properties-config.xml")
 3 public class AppConfig {
 4  
 5     @Value("${jdbc.url}")
 6     private String url;
 7  
 8     @Value("${jdbc.username}")
 9     private String username;
10  
11     @Value("${jdbc.password}")
12     private String password;
13  
14     @Bean
15     public DataSource dataSource() {
16         return new DriverManagerDataSource(url, username, password);
17     }
18 }

源码解析:

 1 AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
 2 if (importResource != null) {
 3     //
 4     String[] resources = importResource.getStringArray("locations");
 5     //
 6     Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
 7     for (String resource : resources) {
 8         //
 9         String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
10         //
11         configClass.addImportedResource(resolvedResource, readerClass);
12     }
13 }

① - 获取@ImportResource注解的value值
② - 获取BeanDefinitionReader
③ - 处理资源路径下的占位符
④ - 将资源和对应的解析器存放至当前配置类的importedResources属性中,它是一个LinkedHashMap

处理@Bean注解

此处处理的是在配置类中具有@Bean注解的方法

 1 //
 2 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
 3 for (MethodMetadata methodMetadata : beanMethods) {
 4     //
 5     configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
 6 }
 7  
 8 //
 9 private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
10     for (SourceClass ifc : sourceClass.getInterfaces()) {
11         Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
12         for (MethodMetadata methodMetadata : beanMethods) {
13             if (!methodMetadata.isAbstract()) {
14                 // A default method or other concrete method on a Java 8+ interface...
15                 configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
16             }
17         }
18         processInterfaces(configClass, ifc);
19     }
20 }
21  
22 //
23 if (sourceClass.getMetadata().hasSuperClass()) {
24     String superclass = sourceClass.getMetadata().getSuperClassName();
25     if (superclass != null && !superclass.startsWith("java") &&
26             !this.knownSuperclasses.containsKey(superclass)) {
27         this.knownSuperclasses.put(superclass, configClass);
28         // Superclass found, return its annotation metadata and recurse
29         return sourceClass.getSuperClass();
30     }
31 }

① - 获取所有具有@Bean注解的方法
② - 将获取到的方法包装为BeanMethod对象(表示一个具有@Bean注解的@Configuration类的方法)保存到当前配置类的beanMethods属性中
④ - 处理接口中具有@Bean注解的方法
⑤ - 处理父类中具有@Bean注解的方法

取出@Configuration

直接从Parser中取出之前解析时缓存的配置类,因为这段代码在do-while循环中,因此首先移除已处理的。

1 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
2 configClasses.removeAll(alreadyParsed);

构建BeanDefinitionReader

若Reader为空,则创建,用于读取配置中的BeanDefinition

1 if (this.reader == null) {
2     this.reader = new ConfigurationClassBeanDefinitionReader(
3             registry, this.sourceExtractor, this.resourceLoader, this.environment,
4             this.importBeanNameGenerator, parser.getImportRegistry());
5 }

@Configuration读取BeanDefinition

前面对各种注解的的解析最终并没有处理解析的结果,而是将其放在了ConfigurationClass对象的属性当中存储,在这里将通过Reader来处理这些不同来源的BeanDefinition。

 1 this.reader.loadBeanDefinitions(configClasses);
 2 alreadyParsed.addAll(configClasses);
 3  
 4  
 5 public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
 6     TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
 7     //
 8     for (ConfigurationClass configClass : configurationModel) {
 9         //
10         loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
11     }
12 }

① - 遍历所有的@Configuration
② - 从@Configuration读取BeanDefinition

 1 private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
 2     //
 3     if (trackedConditionEvaluator.shouldSkip(configClass)) {
 4         String beanName = configClass.getBeanName();
 5         if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
 6             this.registry.removeBeanDefinition(beanName);
 7         }
 8         this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
 9         return;
10     }
11  
12     //
13     if (configClass.isImported()) {
14         registerBeanDefinitionForImportedConfigurationClass(configClass);
15     }
16     
17     //
18     for (BeanMethod beanMethod : configClass.getBeanMethods()) {
19         loadBeanDefinitionsForBeanMethod(beanMethod);
20     }
21  
22     //
23     loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
24     
25     //
26     loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
27 }

① - 是否需要跳过
② - 当前配置类本身是否通过@Import导入,若有则将自身注册为BeanDefinition
③ - 当前配置类中是否有@Bean注解修饰的方法,若有则处理
④ - 加载从@ImportResource导入的XML文件中定义的Bean
⑤ - 加载从@Import导入的BeanDefinition

合并已处理的BeanDefinition

 1 //
 2 String[] candidateNames = registry.getBeanDefinitionNames();
 3  
 4 if (registry.getBeanDefinitionCount() > candidateNames.length) {
 5     //
 6     String[] newCandidateNames = registry.getBeanDefinitionNames();
 7     //
 8     Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
 9     //
10     Set<String> alreadyParsedClasses = new HashSet<>();
11     //
12     for (ConfigurationClass configurationClass : alreadyParsed) {
13         alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
14     }
15     
16     //
17     for (String candidateName : newCandidateNames) {
18         //
19         if (!oldCandidateNames.contains(candidateName)) {
20             //
21             BeanDefinition bd = registry.getBeanDefinition(candidateName);
22             if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
23                     !alreadyParsedClasses.contains(bd.getBeanClassName())) {
24                 candidates.add(new BeanDefinitionHolder(bd, candidateName));
25             }
26         }
27     }
28     //
29     candidateNames = newCandidateNames;
30 }

① - candidateNames 在方法的一开始就从registry中获取已经处理过的BeanDefinition名称
② - newCandidateNames 表示本次从配置类的解析中加载完毕BeanDefinition之后的BeanDefinition名称列表,它包含第一步里面的名称
③ - 将第一步的名称列表转换为Set集合
④ - 声明已解析的集合,此处用Set因为它可以保证元素不重复
⑤ - 遍历本次已经处理的所有类集合,将其加入第四步声明的Set集合内
⑥ - 遍历registry中现有的列表
⑦ - 当前的BeanDefinition必须是本次代码执行时加入的才进行处理
⑧ - 获取当前处理的类,判断是否为Configuration,并设置FULL模式和LITE模式
⑨ - 获取全部已经处理的类赋值给candidateNames

关于@SpringBootApplication注解

看到这里可能读者会有疑问:为什么入口处的@SpringBootApplication注解没有解析?每一个SpringBoot应用都能看到它的身影,它是在哪里被解析的呢?要弄明白它的功能还得从注解本身讲起。

 1 /**
 2  * 指明了它是一个配置类,可以声明一个或者多个@Bean方法,并且触发自动扫描和配置
 3  * 等效于同时使用@Configuration、@ComponentScan、@EnableAutoConfiguration三个注解
 4  * Indicates a {@link Configuration configuration} class that declares one or more
 5  * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
 6  * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
 7  * annotation that is equivalent to declaring {@code @Configuration},
 8  * {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
 9  *
10  * @author Phillip Webb
11  * @author Stephane Nicoll
12  * @since 1.2.0
13  */
14 @Target(ElementType.TYPE)
15 @Retention(RetentionPolicy.RUNTIME)
16 @Documented
17 @Inherited
18 @SpringBootConfiguration
19 @EnableAutoConfiguration
20 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
21 public @interface SpringBootApplication {
22  
23     /**
24      * 排除某些自动配置类
25      * Exclude specific auto-configuration classes such that they will never be applied.
26      * @return the classes to exclude
27      */
28     @AliasFor(annotation = EnableAutoConfiguration.class)
29     Class<?>[] exclude() default {};
30  
31     /**
32      * 排除某些自动配置类名称
33      * Exclude specific auto-configguration class names such that they will never be
34      * applied.
35      * @return the class names to exclude
36      * @since 1.3.0
37      */
38     @AliasFor(annotation = EnableAutoConfiguration.class)
39     String[] excludeName() default {};
40  
41     /**
42      * 用于扫描带@Component注解的基础包路径
43      * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
44      * for a type-safe alternative to String-based package names.
45      * <p>
46      * <strong>Note:</strong> this setting is an alias for
47      * {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
48      * scanning or Spring Data {@link Repository} scanning. For those you should add
49      * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
50      * {@code @Enable...Repositories} annotations.
51      * @return base packages to scan
52      * @since 1.3.0
53      */
54     @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
55     String[] scanBasePackages() default {};
56  
57     /**
58      * basePackages的类型安全的替代方法,将扫描每个类的包路径
59      * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
60      * scan for annotated components. The package of each class specified will be scanned.
61      * <p>
62      * Consider creating a special no-op marker class or interface in each package that
63      * serves no purpose other than being referenced by this attribute.
64      * <p>
65      * <strong>Note:</strong> this setting is an alias for
66      * {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
67      * scanning or Spring Data {@link Repository} scanning. For those you should add
68      * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
69      * {@code @Enable...Repositories} annotations.
70      * @return base packages to scan
71      * @since 1.3.0
72      */
73     @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
74     Class<?>[] scanBasePackageClasses() default {};
75  
76 }

以上是这个注解的全部内容,通过注释可以得知它也是一个配置类,无非就多了自动扫描和自动配置的功能。当前注解类中并未看到@Configuration注解,其实它隐藏在@SpringBootConfiguration注解中

1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @Configuration
5 public @interface SpringBootConfiguration {
6  
7 }

自动扫描是通过添加@ComponentScan注解实现,自动配置是通过添加@EnableAutoConfiguration注解来实现。同时又对这两个注解重新指定了显式的别名。

提示:
关于@AliasFor注解这里简单介绍一下,有助于理解代码含义。此处应用了在元注解属性中的显示别名

举例说明:
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
这个注解在@AliasFor内部填充了annotation和basePackages属性,并且声明在scanBasePackages方法上。表
示scanBasePackages在当前@SpringBootApplication注解中代表了@ComponentScan注解中的basePackages属性,是它的显式别名。
也可以说是是scanBasePackages覆盖了basePackages

也就是说@SpringBootApplication注解自身并没有任何方法,它仅仅是组合了多个注解,并通过覆盖别名的方法提供了对被组合注解的属性值设置。

再啰嗦点就是:
@SpringBootApplication注解的scanBasePackageClasses代表@ComponentScan中的basePackageClasses

1 // 写法对比
2 @SpringBootApplication(scanBasePackageClasses = {Test.class})
3 @ComponentScan(basePackageClasses = {Test.class})
4 // 这两种写法功能完全一致

再提一点

我们可以看到,扫描包路径可以配置String类型的包名(通过scanBasePackages属性来配置)、配置Class类型的类(通过scanBasePackageClasses)Spring代码中的注释说道后者是前者类型安全的替代。怎么理解呢?其实也蛮直观的,当你使用String类型的包路径时它是一个字符串,在编译过程即便写错了,它也不会提示,只会在解析到这个包的时候因为包名错误而无法查找到想要加载的Bean,也不会报错。而使用类来配置的话若它不存在在编译的时候就不会通过。提早发现编写错误。那么当我们使用一个类来配置的时候,它会扫描什么内容呢?答案是它将会扫描此类所在的包下所有的类,包括子包中的类。

通过上面的解释,想必大家可以知道为何在前面篇章中没有提到@SpringBootApplication注解的解析了。

关于@EnableAutoConfiguration它启动了SpringBoot的自动配置,这块内容单独提取出来进行分析,此处只需要知道加入了这个注解,SpringBoot将会开启自动配置即可。

关于@EnableAutoConfiguration注解

这个注解是用于SpringBoot开启自动配置,通常使用@SpringBootApplication来启用它,在前一章节介绍@SpringBootApplication中可以看到是包含了@EnableAutoConfiguration注解的。因此当使用了@SpringBootApplication注解时无需再添加@EnableAutoConfiguration注解。
自动配置类是常规的Spring配置bean,它们是使用SpringFactoriesLoader机制来获取的。

 1 @Target(ElementType.TYPE)
 2 @Retention(RetentionPolicy.RUNTIME)
 3 @Documented
 4 @Inherited
 5 @AutoConfigurationPackage
 6 @Import(AutoConfigurationImportSelector.class)
 7 public @interface EnableAutoConfiguration {
 8  
 9     // 开启自动配置属性,默认为true
10     String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
11  
12     /**
13      * 排除不加载的配置类
14      * Exclude specific auto-configuration classes such that they will never be applied.
15      * @return the classes to exclude
16      */
17     Class<?>[] exclude() default {};
18  
19     /**
20      * 排除不加载的配置类名称
21      * Exclude specific auto-configuration class names such that they will never be
22      * applied.
23      * @return the class names to exclude
24      * @since 1.3.0
25      */
26     String[] excludeName() default {};
27  
28 }

首先看到这个注解上面使用了@AutoConfigurationPackage注解,它用于表示使用该注解的类所在的包将被作为加载配置的路径。

1 @Target(ElementType.TYPE)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 @Inherited
5 @Import(AutoConfigurationPackages.Registrar.class)
6 public @interface AutoConfigurationPackage {
7  
8 }

注解的源码中又使用了@Import注解,并导入了AutoConfigurationPackages.Registrar.class,用于储存从导入配置类里面获取的基础包。究竟是什么包呢?还记得在前面学到的,当所有的@Configuration解析完毕之后才开始执行解析过程中获取的资源吗?在@Configuration读取BeanDefinition
章节的loadBeanDefinitionsForConfigurationClass()方法的第⑤步,调用了loadBeanDefinitionsFromRegistrars()方法

再看下EnableAutoConfiguration导入的AutoConfigurationImportSelector.class

 1 /**
 2  * {@link DeferredImportSelector} to handle {@link EnableAutoConfiguration
 3  * auto-configuration}. This class can also be subclassed if a custom variant of
 4  * {@link EnableAutoConfiguration @EnableAutoConfiguration} is needed.
 5  *
 6  * @author Phillip Webb
 7  * @author Andy Wilkinson
 8  * @author Stephane Nicoll
 9  * @author Madhura Bhave
10  * @since 1.3.0
11  * @see EnableAutoConfiguration
12  */
13 public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
14     // 省略部分代码
15 }

从类注释上可以看出它是用于处理自动配置的。也就是说使用了@EnableAutoConfiguration注解就会导入这个自动处理配置的类,实现了一系列的Aware接口,表示它会被调用相关接口来设置Aware的对象,又实现了DeferredImportSelector接口,因此在所有@Configuration执行完毕之后将会被执行到selectImports()方法。

总结

SpringBoot中对于框架外的类加载从容器刷新阶段中的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)方法开始。用于调用BeanFactoryPostProcessor,位于org.springframework.context.annotation包下的ConfigurationClassPostProcessor.class实现了这个接口。
ConfigurationClassPostProcessor类并未直接实现BeanFactoryPostProcessor,而是实现了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor。所以需要搞清楚他们各自方法的执行顺序。

在加载BeanDefinition之前,先获取所有的@Configuration,按照它的优先级排序。接着循环解析这些配置类,在解析的过程中又根据不同的注解来加载不同的内容。从而完成整个应用内部的BeanDefinition获取。

 

posted @ 2022-07-05 20:29  Boblim  阅读(2232)  评论(0编辑  收藏  举报