玩转 Spring Boot 原理篇(自动装配源码剖析)(十二)

2022-09-23 20:48:39 浏览数 (1)

0. 

0.1. Spring Boot 自动装配原理

  • Spring Boot 通过 @EnableAutoConfiguration 注解开启自动配置,@EnableAutoConfiguration 注解可以帮助 SpringBoot 应用将所有符合条件的 @Configuration 配置都加载到 IOC 容器,就跟“八爪鱼”一样。
  • 借助 Spring 框架工具类 SpringFactoriesLoader 的支持,可以智能的加载 META-INF/spring.factories 配置文件中注册的各种 XxxAutoConfiguration 类。
  • 当某个 XxxAutoConfiguration 类满足其注解 @Conditional 指定的生效条件时,实例化该 XxxAutoConfiguration 类中定义的 Bean 注入 Spring 容器,就可以完成依赖框架的自动装配。

1. Spring Boot 源码剖析

Spring Boot应用启动时会调用 SpringApplication.run(String... args) 方法。

run 方法内部会调用 refreshContext(context) 方法来完成自动装配的操作。

跟剥洋葱一样,通过 debug 的方式一层层往里跟,最终会调用ConfigurationClassParser 类来完成所有配置类的解析,其所有的解析逻辑在 parser.parse(candidates) 方法中。

调用重载的 parse 方法来完成解析。

接着调用  processConfigurationClass 方法来完成配置类解析处理。

接着调用 doProcessConfigurationClass 方法,此方法是支持注解配置的核心逻辑处理,方法内部会调用 processImports(configClass, sourceClass, getImports(sourceClass), filter, true) 方法进行递归解析,获取导入的配置类(@Import)。

接着看看获取配置类的相关逻辑,此时会看到所有的 bean 都以导入的方式被加载进去。

继续 Debug,会调用 ConfigurationClassParser 中的 parse 方法中的最后一行,继续跟进 this.deferredImportSelectorHandler.process() 方法。

继续 Debug,会调用 DeferredImportSelectorHandler 的 process 方法。

继续 Debug,会调用 DeferredImportSelectorGroupingHandler 的 processGroupImports 方法。

processGroupImports() 内部,会调用 grouping.getImports() 方法。

grouping.getImports()方法内部会调用 this.group.process方法。

this.group.process 方法可以说是自动装配的重点了。

getAutoConfigurationEntry 方法详细解释一下

代码语言:javascript复制
/** * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata} * of the importing {@link Configuration @Configuration} class. * @param annotationMetadata the annotation metadata of the configuration class * @return the auto-configurations that should be imported */protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {   if (!isEnabled(annotationMetadata)) {      return EMPTY_ENTRY;   }   AnnotationAttributes attributes = getAttributes(annotationMetadata);   // 通过 SpringFactoriesLoader 类提供的方法加载类路径中的 META-INF 目录下的    // spring.factories 文件中针对 EnableAutoConfiguration 的注册配置类   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);   // 对获得的注册配置类集合进行去重处理,防止多个项目引入同样的配置类   configurations = removeDuplicates(configurations);   // 获得注解中被 exclude 或 excludeName 所排除的类的集合   Set<String> exclusions = getExclusions(annotationMetadata, attributes);   // 检查被排除类是否可实例化,是否被自动注册配置所使用,不符合条件则抛出异常   checkExcludedClasses(configurations, exclusions);   // 从自动配置类集合中去除被排除的类   configurations.removeAll(exclusions);   // 检查配置类的注解是否符合 spring.factories 文件中 AutoConfigurationImportFilter 指定的注解检查条件   configurations = getConfigurationClassFilter().filter(configurations);   // 将筛选完成的配置类和排查的配置类构建为事件类,并传入监听器。监听器的配置在于 spring.factories 文件中   // 通过 AutoConfigurationImportListener 指定   fireAutoConfigurationImportEvents(configurations, exclusions);   return new AutoConfigurationEntry(configurations, exclusions);}

能够发现getCandidateConfigurations 方法中会通过 SpringFactoriesLoader 类来加载类路径中的 META-INF 目录下的 spring.factories 文件中针对 EnableAutoConfiguration 的注册配置类。

为了调试方便,在源码中的 process 方法上里加入了打印输出。

运行后,此时控制台输出如下。

代码语言:javascript复制
AutoConfigurationImportSelector.AutoConfigurationGroup.process() , entries = {org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.aop.AopAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration=smoketest.simple.SampleSimpleApplication, org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration=smoketest.simple.SampleSimpleApplication}

2. 例行回顾

本文采取 Debug 的方式跟了一下 Spring Boot 自动装配的源码,旨在感受一下自动装配的实现方式,其实这种自动装配的思想,在开发轮子时或许能够借鉴一下,会对轮子的扩展带来质的改变。

为了方便记忆,把 Spring Boot 自动装配繁琐的流程抽象一下。

另外 Spring Boot 自动装配源码 Debug 主线,感兴趣可以自行跟一下源码。

0 人点赞