Spring自动配置的实现原理 Spring Boot 的自动配置是其最受欢迎的特性之一。理解自动配置原理,有助于自定义 Starter 和排查配置问题。
自动配置的入口 @SpringBootApplication @SpringBootApplication public class Application { public static void main (String[] args) { SpringApplication.run(Application.class, args); } }
等价于 :
@Configuration @EnableAutoConfiguration @ComponentScan public class Application { }
@EnableAutoConfiguration @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}
核心 :@Import(AutoConfigurationImportSelector.class)
AutoConfigurationImportSelector 加载流程 public class AutoConfigurationImportSelector implements DeferredImportSelector , BeanClassLoaderAware, ... { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
读取 spring.factories protected List<String> getCandidateConfigurations (AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories" ); return configurations; }
spring.factories 示例 :
org.springframework.boot.autoconfigure.EnableAutoConfiguration =\ com.example.MyAutoConfiguration,\ com.example.OtherAutoConfiguration
过滤配置类 protected AutoConfigurationEntry getAutoConfigurationEntry (AnnotationMetadata metadata) { List<String> configurations = getCandidateConfigurations(metadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(metadata, attributes); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry (configurations, exclusions); }
条件注解 常用条件注解
注解
条件
@ConditionalOnClass
classpath 中存在指定类
@ConditionalOnMissingClass
classpath 中不存在指定类
@ConditionalOnBean
容器中存在指定 Bean
@ConditionalOnMissingBean
容器中不存在指定 Bean
@ConditionalOnProperty
指定属性满足条件
@ConditionalOnResource
存在指定资源
@ConditionalOnWebApplication
是 Web 应用
@ConditionalOnExpression
SpEL 表达式为 true
示例 @Configuration @ConditionalOnClass(DataSource.class) @ConditionalOnMissingBean(DataSource.class) @EnableConfigurationProperties(DataSourceProperties.class) public class DataSourceAutoConfiguration { @Bean @ConditionalOnMissingBean public DataSource dataSource (DataSourceProperties properties) { return DataSourceBuilder.create() .url(properties.getUrl()) .username(properties.getUsername()) .password(properties.getPassword()) .build(); } }
自定义 Starter 创建步骤 1. 创建自动配置类 @Configuration @ConditionalOnClass(MyService.class) @EnableConfigurationProperties(MyProperties.class) public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService (MyProperties properties) { return new MyService (properties.getName()); } }
2. 创建配置属性类 @ConfigurationProperties(prefix = "my.service") public class MyProperties { private String name = "default" ; private boolean enabled = true ; }
3. 创建 spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration =\ com.example.autoconfigure.MyAutoConfiguration
4. 使用 Starter <dependency > <groupId > com.example</groupId > <artifactId > my-spring-boot-starter</artifactId > <version > 1.0.0</version > </dependency >
my: service: name: myApp enabled: true
自动配置报告 查看生效的自动配置 logging.level.org.springframework.boot.autoconfigure=DEBUG java -jar app.jar --debug
自动配置报告 Positive matches: ----------------- DataSourceAutoConfiguration matched: - @ConditionalOnClass found required classes 'DataSource', ... - @ConditionalOnMissingBean (types: DataSource; SearchStrategy: all) did not find any beans Negative matches: ----------------- ActiveMQAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory'
排除自动配置 方式1:注解排除 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) public class Application { }
方式2:配置文件排除 spring: autoconfigure: exclude: - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
自动配置原理总结 @SpringBootApplication └── @EnableAutoConfiguration └── @Import(AutoConfigurationImportSelector) └── selectImports() ├── 读取 META-INF/spring.factories ├── 加载所有 EnableAutoConfiguration 类 ├── 排除指定配置 └── @Conditional 过滤 ├── @ConditionalOnClass ├── @ConditionalOnBean └── @ConditionalOnProperty
常见问题 1. 自动配置不生效 排查 :
2. 配置冲突 解决 :
@Bean @ConditionalOnMissingBean public MyService myService () { return new MyService (); }
3. 加载顺序 @AutoConfigureAfter(DataSourceAutoConfiguration.class) @AutoConfigureBefore(WebMvcAutoConfiguration.class) public class MyAutoConfiguration { }
总结 Spring Boot 自动配置的核心机制:
spring.factories :注册自动配置类
@Conditional :条件过滤,按需加载
@EnableConfigurationProperties :绑定配置
@ConditionalOnMissingBean :允许用户覆盖
这个设计使得 Spring Boot 项目可以做到零配置启动,同时保留充分的自定义能力。