注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.2.12.RELEASE进行学习分析,版本不同可能会有细微差别。
1. 前言 关于配置文件可以配置的内容,在Spring Boot 官方网站已经提供了完整的配置和解释。
可以这么说,Spring Boot的一大精髓就是自动装配 ,为开发省去了大量的配置时间。那么Springboot自动装配是怎么实现的呢?
1. @SpringBootApplication 跟着Spring Boot启动类的注解@SpringBootApplication
进行源码跟踪,可以找到自动装配的原理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @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 { }
可以看到@SpringBootApplication
是个组合注解,其中包括以下:
2. @EnableAutoConfiguration 继续跟踪,查看@EnableAutoConfiguration
源码,里面比较重要的是@Import
,导入一个翻译名为自动装配的选择器的类,这个类起始就是自动装配的加载选择器。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration" ; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
继续跟踪AutoConfigurationImportSelector.class
,在这个类中有一个重要的方法getCandidateConfigurations
,用于加载Springboot配置的自动装配类。
方法getAutoConfigurationEntry
会筛选出有效的自动装配类
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 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); } } 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; }
在方法getCandidateConfigurations
中,通过SpringFactoriesLoader.loadFactoryNames(xxx)
去加载配置信息。 它通过SPI机制去加载所有META-INF/spring.factories
配置信息。
随便找一个spring.factories
配置信息如下:
3. @EnableConfigurationProperties 在上面的 debug 里,我们看到了成功加载的自动装配,目前只看到了配置类,却还没有发现自动装配值,随便选择一个 AutoConfiguration 查看源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Configuration( proxyBeanMethods = false ) @AutoConfigureOrder(-2147483648) @ConditionalOnClass({ServletRequest.class}) @ConditionalOnWebApplication( type = Type.SERVLET ) @EnableConfigurationProperties({ServerProperties.class}) @Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class}) public class ServletWebServerFactoryAutoConfiguration { }
需要注意的是 @EnableConfigurationProperties(ServerProperties.class)
, 他的意思是启动指定类的 ConfigurationProperties
功能;将配置文件中对应的值和 ServerProperties
绑定起来;并把 ServerProperties
加入到 IOC 容器中。
再来看一下ServerProperties
1 2 3 4 5 6 7 8 @ConfigurationProperties( prefix = "server", ignoreUnknownFields = true ) public class ServerProperties { }
4. 总结
SpringBoot 启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration 。
@EnableAutoConfiguration 给容器导入 META-INF/spring.factories 里定义的自动配置类。
筛选有效的自动配置类。
每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能 。
5. 附录
@Conditional 扩展注解
作用(判断是否满足当前指定条件)
@ConditionalOnJava
系统的 java 版本是否符合要求
@ConditionalOnBean
容器中存在指定 Bean
@ConditionalOnMissingBean
容器中不存在指定 Bean
@ConditionalOnExpression
满足 SpEL 表达式指定
@ConditionalOnClass
系统中有指定的类
@ConditionalOnMissingClass
系统中没有指定的类
@ConditionalOnSingleCandidate
容器中只有一个指定的 Bean,或者这个 Bean 是首选 Bean
@ConditionalOnProperty
系统中指定的属性是否有指定的值
@ConditionalOnResource
类路径下是否存在指定资源文件
@ConditionalOnWebApplication
当前是 web 环境
@ConditionalOnNotWebApplication
当前不是 web 环境
@ConditionalOnJndi
JNDI 存在指定项