自动配置原理
问题
Spring Boot 的自动配置是如何实现的?@EnableAutoConfiguration 的工作原理是什么?
答案
自动配置全景
自动配置是 Spring Boot 的核心特性——约定优于配置。引入依赖后,Spring Boot 自动完成相关组件的配置,无需手动编写大量 XML 或 Java Config。
@SpringBootApplication 拆解
@SpringBootConfiguration // = @Configuration,标记为配置类
@EnableAutoConfiguration // 开启自动配置(核心)
@ComponentScan // 扫描当前包及子包
public @interface SpringBootApplication {
}
@EnableAutoConfiguration 原理
@Import(AutoConfigurationImportSelector.class) // 关键:导入选择器
public @interface EnableAutoConfiguration {
// exclude:排除特定的自动配置类
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationImportSelector 的核心流程:
public class AutoConfigurationImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
// 1. 从 META-INF 目录下加载自动配置类的全限定名
List<String> configurations = getCandidateConfigurations(metadata, attributes);
// Spring Boot 2.7+:读取 META-INF/spring/xxx.imports 文件
// Spring Boot 2.7 之前:读取 META-INF/spring.factories
// 2. 去重
configurations = removeDuplicates(configurations);
// 3. 排除用户指定的自动配置
Set<String> exclusions = getExclusions(metadata, attributes);
configurations.removeAll(exclusions);
// 4. 过滤(@Conditional 条件判断)
configurations = getConfigurationClassFilter().filter(configurations);
// 5. 返回满足条件的自动配置类
return configurations.toArray(new String[0]);
}
}
条件注解(@Conditional)
自动配置类通过条件注解判断是否生效:
| 条件注解 | 含义 |
|---|---|
@ConditionalOnClass | classpath 中有指定类才生效 |
@ConditionalOnMissingClass | classpath 中没有指定类才生效 |
@ConditionalOnBean | 容器中有指定 Bean 才生效 |
@ConditionalOnMissingBean | 容器中没有指定 Bean 才生效(最常用) |
@ConditionalOnProperty | 配置属性满足指定值才生效 |
@ConditionalOnWebApplication | Web 应用环境才生效 |
@ConditionalOnExpression | SpEL 表达式为 true 才生效 |
以 Redis 自动配置为例
// 条件1:classpath 中有 RedisOperations 类(引入了 spring-data-redis 依赖)
@ConditionalOnClass(RedisOperations.class)
// 绑定配置属性 spring.data.redis.*
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
// 条件2:容器中没有 redisTemplate Bean(用户未自定义)
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory factory) {
return new StringRedisTemplate(factory);
}
}
用户自定义的 Bean 始终优先于自动配置。这是因为 @ConditionalOnMissingBean 的存在——当用户已经注册了同类型的 Bean,自动配置就会跳过。
自动配置的加载顺序
通过注解控制配置类的加载顺序:
@AutoConfiguration(
after = DataSourceAutoConfiguration.class, // 在数据源之后
before = JpaRepositoriesAutoConfiguration.class // 在 JPA 之前
)
public class MyAutoConfiguration {
// ...
}
自定义自动配置
// 1. 编写自动配置类
@AutoConfiguration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties.getEndpoint());
}
}
// 2. 配置属性类
@ConfigurationProperties(prefix = "my.service")
public class MyProperties {
private String endpoint = "http://localhost:8080";
// getter/setter
}
com.example.MyAutoConfiguration
常见面试问题
Q1: Spring Boot 自动配置的原理是什么?
答案:
@SpringBootApplication 包含 @EnableAutoConfiguration,它通过 @Import(AutoConfigurationImportSelector) 导入一个选择器。选择器从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中读取所有候选自动配置类,然后通过 @Conditional 系列注解进行条件过滤,只有满足条件(如 classpath 有对应依赖、容器中没有用户自定义的 Bean)的自动配置类才会生效。
Q2: 如何禁用某个自动配置?
答案:
三种方式:
// 方式1:@SpringBootApplication 的 exclude 属性
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
// 方式2:配置文件
// spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
// 方式3:@EnableAutoConfiguration 的 exclude
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
Q3: @ConditionalOnMissingBean 的作用?
答案:
表示容器中不存在指定类型的 Bean 时,当前 @Bean 方法才会执行。这保证了用户自定义的 Bean 始终优先,自动配置只作为兜底默认值。
Q4: spring.factories 和 AutoConfiguration.imports 有什么区别?
答案:
META-INF/spring.factories是 Spring Boot 2.7 之前的方式,所有 SPI 机制共用一个文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports是 2.7+ 推荐的方式,每行一个配置类全限定名,更清晰- Spring Boot 3.0 完全移除了
spring.factories中自动配置的支持
Q5: 自动配置类的加载顺序如何控制?
答案:
通过 @AutoConfiguration 注解的 before 和 after 属性,或使用 @AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder 注解来控制。例如 MyBatis 的自动配置需要在 DataSource 自动配置之后执行。
相关链接
- Spring Boot 官方文档 - Auto-configuration
- Spring 常用注解 - @Conditional 系列注解
- IoC 容器与依赖注入 - BeanFactory 与 Bean 注册