跳到主要内容

自动配置原理

问题

Spring Boot 的自动配置是如何实现的?@EnableAutoConfiguration 的工作原理是什么?

答案

自动配置全景

自动配置是 Spring Boot 的核心特性——约定优于配置。引入依赖后,Spring Boot 自动完成相关组件的配置,无需手动编写大量 XML 或 Java Config。

@SpringBootApplication 拆解

SpringBootApplication.java
@SpringBootConfiguration   // = @Configuration,标记为配置类
@EnableAutoConfiguration // 开启自动配置(核心)
@ComponentScan // 扫描当前包及子包
public @interface SpringBootApplication {
}

@EnableAutoConfiguration 原理

EnableAutoConfiguration.java
@Import(AutoConfigurationImportSelector.class) // 关键:导入选择器
public @interface EnableAutoConfiguration {
// exclude:排除特定的自动配置类
Class<?>[] exclude() default {};
String[] excludeName() default {};
}

AutoConfigurationImportSelector 的核心流程:

AutoConfigurationImportSelector.java(简化)
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)

自动配置类通过条件注解判断是否生效:

条件注解含义
@ConditionalOnClassclasspath 中指定类才生效
@ConditionalOnMissingClassclasspath 中没有指定类才生效
@ConditionalOnBean容器中指定 Bean 才生效
@ConditionalOnMissingBean容器中没有指定 Bean 才生效(最常用)
@ConditionalOnProperty配置属性满足指定值才生效
@ConditionalOnWebApplicationWeb 应用环境才生效
@ConditionalOnExpressionSpEL 表达式为 true 才生效

以 Redis 自动配置为例

RedisAutoConfiguration.java(简化)
// 条件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
}
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
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.imports2.7+ 推荐的方式,每行一个配置类全限定名,更清晰
  • Spring Boot 3.0 完全移除了 spring.factories 中自动配置的支持

Q5: 自动配置类的加载顺序如何控制?

答案

通过 @AutoConfiguration 注解的 beforeafter 属性,或使用 @AutoConfigureBefore@AutoConfigureAfter@AutoConfigureOrder 注解来控制。例如 MyBatis 的自动配置需要在 DataSource 自动配置之后执行。

相关链接