Spring Boot 的“自动配置”(Auto-Configuration)原理
Spring Boot 自动配置(Auto-Configuration)是其核心特性之一,它体现了 “约定优于配置” (Convention over Configuration) 的设计理念。
简单来说,它的原理就是:在应用启动时,Spring Boot 会根据你引入的 Jar 包(Classpath)、配置文件(Properties/YAML)以及你自定义的 Bean,自动猜测并配置你可能需要的 Bean 到 Spring 容器中。
下面深入源码和机制,分步骤解析其底层原理:
1. 入口:@SpringBootApplication
一切始于主启动类上的 @SpringBootApplication 注解。这是一个组合注解,其中最关键的是 @EnableAutoConfiguration。
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@SpringBootApplication 实际上包含了三个核心注解:
@SpringBootConfiguration:声明当前类是一个配置类。@ComponentScan:扫描当前包及其子包下的组件。@EnableAutoConfiguration:开启自动配置的核心。
2. 核心开关:@EnableAutoConfiguration
@EnableAutoConfiguration 的作用是告诉 Spring Boot:“请帮我自动配置 Bean”。它内部使用了 @Import 注解来导入配置加载器。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) // 关键点
public @interface EnableAutoConfiguration {
// ...
}
这里的关键是 @Import(AutoConfigurationImportSelector.class)。
3. 选择器:AutoConfigurationImportSelector
AutoConfigurationImportSelector 类实现了 DeferredImportSelector 接口。它的主要职责是在 Spring 容器启动过程中,根据一定的规则选择需要导入的配置类。
其核心流程如下:
加载所有候选配置类:
它会去寻找所有 Jar 包中特定的配置文件,读取其中列出的自动配置类全限定名。- Spring Boot 2.7 之前:读取
META-INF/spring.factories文件(Key 为EnableAutoConfiguration)。 - Spring Boot 2.7 及 3.x:读取
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。
例子(spring-boot-autoconfigure.jar 中):
里面包含了大量的配置类,如RedisAutoConfiguration、JdbcTemplateAutoConfiguration等。- Spring Boot 2.7 之前:读取
去重与排除:
去除重复的配置类,并根据@EnableAutoConfiguration(exclude=...)排除掉用户明确不需要的配置类。按需过滤(核心逻辑):
虽然加载了上百个自动配置类,但不能全部生效,否则应用会极其臃肿且报错。这里就需要用到 条件注解(Conditional Annotations)。
4. 智能过滤:@Conditional 派生注解
这是自动配置最“智能”的地方。每个自动配置类(如 RedisAutoConfiguration)上面都挂满了 @Conditional 系列注解。只有满足所有条件,该配置类才会生效,Bean 才会被注册到容器中。
常见的条件注解包括:
@ConditionalOnClass:当 Classpath 中存在指定的类时才生效。(例如:只有引入了spring-boot-starter-data-redis,Classpath 里有了 Redis 相关类,Redis 的自动配置才会生效)。@ConditionalOnMissingBean:当容器中没有用户自定义的同类型 Bean 时才生效。(这允许用户手动定义 Bean 来覆盖默认配置)。@ConditionalOnProperty:当配置文件中有指定的属性且值为特定值时才生效。@ConditionalOnWebApplication:只有在 Web 应用环境下才生效。
举个例子(HttpEncodingAutoConfiguration):
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) // 1. 必须是 Web 应用
@ConditionalOnClass(CharacterEncodingFilter.class) // 2. 必须有这个过滤器类
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) // 3. 配置没关
public class HttpEncodingAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 4. 如果用户没自己配,我就配一个
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
// 设置编码...
return filter;
}
}
5. 属性绑定:@ConfigurationProperties
自动配置类通常需要读取 application.properties 或 application.yml 中的配置。这是通过 @ConfigurationProperties 实现的。
- 定义一个 Properties 类(如
ServerProperties),使用@ConfigurationProperties(prefix = "server")绑定配置文件前缀。 - 在自动配置类上使用
@EnableConfigurationProperties(ServerProperties.class)激活它。 - 自动配置类就可以直接注入
ServerProperties并使用其中的值来初始化 Bean。
总结:自动配置的完整流程
- 启动:Spring Boot 应用启动,加载主配置类,解析
@EnableAutoConfiguration。 - 导入:
AutoConfigurationImportSelector被调用。 - 扫描:扫描所有 Jar 包下的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(或旧版的spring.factories),获取所有候选的自动配置类列表(通常有 100+ 个)。 - 筛选:
- 排除用户显式 exclude 的类。
- 利用
@Conditional系列注解进行过滤(检查类路径有没有对应的 Jar 包、检查有没有用户自定义的 Bean、检查配置文件属性)。
- 注册:将筛选后剩下的、符合条件的配置类加载到 Spring IOC 容器中,这些配置类中定义的
@Bean方法被执行,完成组件的自动装配。
一句话总结:
Spring Boot 启动时,通过 spring.factories (或 .imports) 获取所有自动配置类,然后利用 @Conditional 注解根据当前环境(类路径、已有 Bean、配置文件)动态决定哪些配置类生效,从而实现“即插即用”。