1. 起因
使用 springboot 也有些时间, 一直很好奇它如何做到自动配置的, 所以查阅了相关资料并且学习了相关内容, 才写了这篇文章.
2. 分析
1第一步我们从它的启动配置类 (XxxApplication) 收起, 我们进入到他的 @SpringBootApplication 注解.
2我们可以看到如下代码, 由于我们需要找到导致它自动配置的, 所以锁定了 @EnableAutoConfiguration 注解, 那么就可以进入这个注解.
- @Target({ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan(
- excludeFilters = {@Filter(
- type = FilterType.CUSTOM,
- classes = {TypeExcludeFilter.class}
- ), @Filter(
- type = FilterType.CUSTOM,
- classes = {AutoConfigurationExcludeFilter.class}
- )}
- )
- public @interface SpringBootApplication {
- @AliasFor(
- annotation = EnableAutoConfiguration.class
- )
- Class<?>[] exclude() default {};
- @AliasFor(
- annotation = EnableAutoConfiguration.class
- )
- String[] excludeName() default {};
- @AliasFor(
- annotation = ComponentScan.class,
- attribute = "basePackages"
- )
- String[] scanBasePackages() default {};
- @AliasFor(
- annotation = ComponentScan.class,
- attribute = "basePackageClasses"
- )
- Class<?>[] scanBasePackageClasses() default {};
- }
3 我们看到了如下代码, 由于这是一个接口, 而它的实现类我们又不好确定, 所以我们只好从注解入手, 由于 @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited 等都是元注解, 我们可以从 @AutoConfigurationPackage,@Import({AutoConfigurationImportSelector.class})中找到我们想要的, 根据它的中文意思我们可以从 @Import({AutoConfigurationImportSelector.class})(自动有选择的导入配置)出发, 毕竟不是所有的配置都会都如, 而导入那些配置根据项目中使用了那些 starter 决定.
4点入第三步提到的注解, 进入这个类根据方法名我们可以猜测是和这个方法相关, 通过阅读这个代码, 我们可以猜测是和 getAutoConfigurationEntry 这个方法有关, 所以不妨点进去.
- public String[] selectImports(AnnotationMetadata annotationMetadata) {
- if (!this.isEnabled(annotationMetadata)) {
- return NO_IMPORTS;
- } else {
- AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
- AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
- return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
- }
- }
5由于我们需要的配置 Config, 所以大致可以断定是和这个代码有关联 Listconfigurations = this.getCandidateConfigurations(annotationMetadata, attributes);, 所以不妨进到这个 getCandidateConfigurations 方法中去.
- protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
- if (!this.isEnabled(annotationMetadata)) {
- return EMPTY_ENTRY;
- } else {
- AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
- List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
- configurations = this.removeDuplicates(configurations);
- Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
- this.checkExcludedClasses(configurations, exclusions);
- configurations.removeAll(exclusions);
- configurations = this.filter(configurations, autoConfigurationMetadata);
- this.fireAutoConfigurationImportEvents(configurations, exclusions);
- return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
- }
- }
6经过第五步, 我们可以看到如下代码
- protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
- List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
- Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
- return configurations;
- }
不妨看这部分代码, Listconfigurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());, 它的意思是一个加载器通过加载某个工厂获得配置的 List, 因此我们在进入到这个的实现是没有必要的, 可以从参数考虑, 所以锁定在第一个参数, 点进入可以看到如下代码.
- protected Class<?> getSpringFactoriesLoaderFactoryClass() {
- return EnableAutoConfiguration.class;
- }
看到这里可能还是会疑惑? 为啥就自动配置了, 其实我们这个方法 (loadFactoryNames) 是从一个配置文件中读取内容, 它的键是 EnableAutoConfiguration, 而这个配置文件是在如图所示的文件中.
6打开上述文件, 根据上一步的键找它的值, 如图就是 springboot 配置类, 那么项目启动时是不是所有的配置都起作用吗? 不妨进入到某个配置类查看即可. 如图所示的 @ConditionalOnMissingBean 注解表示项目的容器是否有这个 bean, 如果没有这个配置类就不会其作用, 另外我们只要在仔细看这个类首先进行了初始化, 之后它会从配置文件 (application.xml 或者 application.YAML) 中获取值.
注: 如有错误, 欢迎指出.
来源: https://www.cnblogs.com/pavi/p/12437314.html