自动配置遵循“自动配置,按需启用”的工作方式。这部分通过源码分析,记录了自动配置的实现原理。
同时也通过源码阐述如何修改默认配置。
初始加载自动配置类
自动配置类的初始加载是由组合注解@SpringBootApplication
实现的。前面的日志提到过,这个组合注解时由如下三个注解组成的:
1 |
下面逐个解释每个注解
@SpringBootConfiguration
追踪后发现本质是一个@Configuration
。说明此注解表示主类也是一个配置类,是核心配置类。
@ComponentScan
指定包扫描路径
@EnableAutoConfiguration(重点)
追踪可发现,这是由两者注解合成的
1 |
|
下面分开说明
@AutoConfigurationPackage
自动配置包
追踪源码发现重点在于:
1 |
再次追踪Registrar
发现下述代码与之有关。
1 | static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { |
对上述代码打断点(断点位置见注释)后分析其作用:
- 【断点】处发现,
metadata
提供了当前类的全包名(和其他信息),然后通过.getPackageNames()
的方法获取包名,并转成字符串数组。 - 这个字符串数组被传给
register
方法,由register
方法将该包下的组件批量注册
@Import(AutoConfigurationImportSelector.class)
追踪AutoConfigurationImportSelector
。截取其中有关代码
1 | public String[] selectImports(AnnotationMetadata annotationMetadata) { |
这段代码的核心是getAutoConfigurationEntry(annotationMetadata)
。由他获取所有需要导入的组件。追踪这个方法
1 | protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { |
发现重点在于getCandidateConfigurations(annotationMetadata, attributes)
。
对此处断点Debug运行,发现这里获得了127个组件
跟踪getCandidateConfigurations
得到
1 | protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { |
发现这里使用loadFactoryNames
这个工厂加载器加载了某些名字,再追踪
1 | public static List<String> loadFactoryNames(Class<?> factoryType, ClassLoader classLoader){ |
追踪返回值有关的方法loadSpringFactories
,得到如下一个有用的内容:
1 | Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); |
去外部库里面找 “ETA-INF/spring.factories” 目录。我们发现 ring-boot-autoconfigure-2.3.4.RELEASE.jar 库下面有这个文件。里面也看到了那 127个组件。
说明这个方法是将写死的127个场景进行加载。
总结
上述两个注解,共同完成了组件的加载。分别作用如下
@AutoConfigurationPackage
- 利用
register
,将Main程序所在包下所有的包导入
- 利用
@Import(AutoConfigurationImportSelector.class)
- 利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
- 调用List
configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类 - 利用工厂加载 Map<String, List
> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件 - 从META-INF/spring.factories位置来加载一个文件。(默认扫描所有包的目录,spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories)
按需启用自动配置项
上一节中提到的“127个场景”的所有自动配置启动的时候默认全部加载(利用:xxxxAutoConfiguration)。
但是这些场景的配置并不会都启用并注册组件。这是通过jorg.springframework.boot.autoconfigure
目录下所展示的各个包配置文件中的条件装配规则(@Conditional)确定的。最终这些场景会按需配置。
修改默认配置
我们有两种方法修改默认配置,一种是在配置类自己写该组件的@Bean
,场景加载时,通过条件装配发现用户自写相关组件就会采用用户的组件。这是由@ConditionalMissingBean
标签实现。
另一种方法是用户去看这个组件是获取的配置文件什么值就去修改“application.properties”
自动加载流程
- SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 —-> application.properties