Spring Boot 自动装配机制
Spring Boot 自动装配机制
1. 什么是自动装配
自动装配(Auto-Configuration)是 Spring Boot 的核心特性,它能够根据项目依赖自动配置 Spring 应用,实现「约定优于配置」。
核心思想:
- 引入依赖 → 自动配置生效
- 用户可随时覆盖默认配置
2. 核心注解
2.1 @SpringBootApplication
@SpringBootApplication // 组合注解
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}展开为:
@SpringBootConfiguration // 等同于 @Configuration
@EnableAutoConfiguration // 启用自动装配(核心)
@ComponentScan // 扫描当前包及子包2.2 @EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) // 核心!
public @interface EnableAutoConfiguration {
}作用:通过 @Import 导入 AutoConfigurationImportSelector,加载所有自动配置类。
3. 自动装配流程
┌─────────────────────────────────────────────────────────────────┐
│ 1. Spring 容器启动,解析 @SpringBootApplication │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 2. 处理 @EnableAutoConfiguration │
│ → @Import(AutoConfigurationImportSelector.class) │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 3. AutoConfigurationImportSelector.selectImports() 执行 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ① getCandidateConfigurations() │ │
│ │ 从 META-INF/spring.factories 加载所有自动配置类 │ │
│ │ (约 130+ 个) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ② removeDuplicates() │ │
│ │ 去重 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ③ getExclusions() │ │
│ │ 排除用户配置的 exclude │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ④ filter() - 条件过滤(最关键!) │ │
│ │ 根据 @Conditional 过滤,只保留满足条件的 │ │
│ │ 最终约 20-30 个生效 │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 4. 注册符合条件的配置类为 BeanDefinition │
└─────────────────────────────────────────────────────────────────┘4. spring.factories 文件
4.1 文件位置
每个 Spring Boot Starter 的 jar 包中:
META-INF/spring.factories4.2 文件格式
# Spring Boot 2.x 格式
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration4.3 Spring Boot 2.7+/3.x 新格式
新增文件:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports内容格式(每行一个类):
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration5. @Conditional 条件注解
自动配置类通过 @Conditional 系列注解控制是否生效。
5.1 常用条件注解
| 注解 | 检查内容 | 检查时机 |
|---|---|---|
| @ConditionalOnClass | 类路径有某个类 | 早期 |
| @ConditionalOnMissingClass | 类路径没有某个类 | 早期 |
| @ConditionalOnBean | 容器中有某个 Bean | 晚期 |
| @ConditionalOnMissingBean | 容器中没有某个 Bean | 晚期 |
| @ConditionalOnProperty | 配置属性满足条件 | 早期 |
| @ConditionalOnWebApplication | 是 Web 应用 | 早期 |
5.2 @ConditionalOnClass
作用:类路径存在某个类才生效。
@Configuration
@ConditionalOnClass(RedisTemplate.class) // 有 Redis 依赖才生效
public class RedisAutoConfiguration {
}原理:
try {
Class.forName("org.springframework.data.redis.core.RedisTemplate");
return true; // 存在
} catch (ClassNotFoundException e) {
return false; // 不存在,跳过配置
}5.3 @ConditionalOnMissingBean
作用:容器中没有某个 Bean 才生效,实现「用户优先」。
@Bean
@ConditionalOnMissingBean(DataSource.class) // 用户没配置才创建
public DataSource dataSource() {
return new HikariDataSource();
}原理:
String[] beanNames = beanFactory.getBeanNamesForType(DataSource.class);
if (beanNames.length == 0) {
return true; // 没有,创建默认的
}
return false; // 已有,跳过5.4 @ConditionalOnProperty
作用:配置属性满足条件才生效。
@Configuration
@ConditionalOnProperty(name = "spring.redis.enabled", havingValue = "true", matchIfMissing = true)
public class RedisAutoConfiguration {
}5.5 组合使用
@Configuration
@ConditionalOnClass(RedisTemplate.class) // 1. 有依赖
@ConditionalOnProperty(name = "spring.redis.host") // 2. 有配置
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 3. 用户没自定义
public RedisTemplate<String, Object> redisTemplate() {
return new RedisTemplate<>();
}
}6. AutoConfigurationImportSelector
6.1 核心方法
public class AutoConfigurationImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
// 1. 加载所有候选配置类
List<String> configurations = getCandidateConfigurations(metadata, attributes);
// 2. 去重
configurations = removeDuplicates(configurations);
// 3. 排除用户配置的 exclude
Set<String> exclusions = getExclusions(metadata, attributes);
configurations.removeAll(exclusions);
// 4. 条件过滤
configurations = filter(configurations, autoConfigurationMetadata);
return configurations.toArray(new String[0]);
}
}6.2 为什么用 DeferredImportSelector
| 类型 | 执行时机 | 用途 |
|---|---|---|
| ImportSelector | 立即执行 | 普通导入 |
| DeferredImportSelector | 延迟到所有配置类解析完后 | 自动配置 |
关键:延迟执行是为了让用户的自定义 Bean 先注册,这样 @ConditionalOnMissingBean 才能正确判断。
7. @Import 导入三种方式
7.1 导入普通类/配置类
@Import(MyConfig.class)
public class AppConfig {}7.2 导入 ImportSelector
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
return new String[] { "com.example.MyConfig" };
}
}
@Import(MyImportSelector.class)
public class AppConfig {}7.3 导入 ImportBeanDefinitionRegistrar
public class MyBeanRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 手动注册 BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Dog.class);
registry.registerBeanDefinition("dog", builder.getBeanDefinition());
}
}
@Import(MyBeanRegistrar.class)
public class AppConfig {}8. 用户优先原则
Spring Boot 的设计哲学:用户配置优先,自动配置兜底。
8.1 实现方式
| 机制 | 作用 |
|---|---|
| DeferredImportSelector | 自动配置延迟到最后处理 |
| @ConditionalOnMissingBean | 用户没配置才用默认的 |
| 普通 @Import 先处理 | 用户配置先注册 |
8.2 解析顺序
1. @ComponentScan 扫描用户组件
↓
2. 用户的 @Configuration + @Bean 注册
↓
3. 用户的 @Import (非 Deferred) 处理
↓
4. DeferredImportSelector 处理(自动装配)
↓
5. @ConditionalOnMissingBean 检查(此时用户的已注册)8.3 示例
// 用户配置(先注册)
@Configuration
public class MyConfig {
@Bean
public DataSource dataSource() {
return new CustomDataSource(); // 优先使用
}
}
// 自动配置(后注册)
@Configuration
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 检查时用户的已存在 → 跳过
public DataSource dataSource() {
return new HikariDataSource(); // 不会创建
}
}9. 自定义 Starter
9.1 命名规范
- 官方:
spring-boot-starter-xxx - 第三方:
xxx-spring-boot-starter
9.2 创建步骤
- 创建自动配置类
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}- 创建配置属性类
@ConfigurationProperties(prefix = "my.service")
public class MyProperties {
private boolean enabled = true;
private String name = "default";
// getters and setters
}- 注册到 spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration10. 面试要点总结
10.1 自动装配原理一句话
@SpringBootApplication → @EnableAutoConfiguration → @Import(AutoConfigurationImportSelector) → 加载 spring.factories → @Conditional 过滤 → 注册 BeanDefinition
10.2 高频问题
| 问题 | 答案 |
|---|---|
| 自动装配的入口 | @EnableAutoConfiguration |
| 配置类从哪加载 | META-INF/spring.factories |
| 条件过滤的核心注解 | @ConditionalOnClass/OnBean/OnProperty |
| 为什么用户能覆盖 | DeferredImportSelector + @ConditionalOnMissingBean |
| @Import 支持哪些类型 | 普通类、ImportSelector、ImportBeanDefinitionRegistrar |
11. 个人理解
Spring Boot 的自动装配机制不仅完美诠释了"约定大于配置"的核心理念,更在底层架构上严格贯彻了"用户自定义优先"的设计原则。整个流程始于主启动类上的 @SpringBootApplication 复合注解,其核心组件 @EnableAutoConfiguration 通过 @Import 导入了关键的选择器 —— AutoConfigurationImportSelector。
该组件巧妙地实现了 DeferredImportSelector(延迟导入选择器)接口。这一设计利用了 Spring 容器的生命周期特性,强行将自动装配的执行时机"挂起",直到容器完成了所有用户自定义的 @Configuration 配置类和 @ComponentScan 组件的扫描与注册。这种"后发制人"的策略,从根源上保证了用户定义的 Bean 拥有绝对的优先级。
当自动装配流程正式启动时,系统会基于 SPI 机制加载 META-INF 目录下的配置文件(Spring Boot 3.x 为 .imports 文件,旧版本为 spring.factories),一次性获取成百上千个自动配置类的全类名候选名单。随即,Spring 对这份名单展开了严格的"三层筛选漏斗":
环境适配(OnClass):利用类加载器(ClassLoader)结合 ASM 字节码技术,执行
@ConditionalOnClass检查。在不触发类初始化的情况下,通过探测底层依赖 Jar 包是否存在,快速剔除当前环境中不具备运行条件的无效配置。配置意图(OnProperty):检查
@ConditionalOnProperty,确认用户是否在配置文件中显式关闭了某些功能。冲突规避(OnMissingBean):这是最终的守门员。对于幸存的配置类,Spring 解析其内部的
@Bean方法,并执行关键的@ConditionalOnMissingBean检查。它会查询容器当前的BeanDefinitionMap,只有确认容器中确实不存在用户自定义的同类组件时,才会将这些自动配置类转化为BeanDefinition并正式注册。
