在上一文:SpringBoot Starter设计:依赖管理的革命我们已经分享过Starter的设计革命,码友也知道了Starter的设计中有一个"黑盒"---自动装配;简单一点儿来说就是:在程序运行过程中,SpringBoot框架自动根据一些规则帮助开发者注入一些必要的bean,从而简化或降低开发难度。
一、设计哲学:约定优于配置
1. 核心理念
- 传统Spring的配置痛点 :
XML/JavaConfig显式声明Bean导致配置冗余(如DataSource、MVC组件),依赖管理复杂。 - Spring Boot的破局思路 :
固化最佳实践 (如默认Tomcat容器、HikariCP连接池) + 条件化装配(按需激活),减少决策成本。
2. 自动配置的四大设计原则
原则 | 实现机制 | 案例 |
---|---|---|
默认值优先 | 预置优化参数(如server.port=8080 ) |
内嵌Tomcat无需显式配置 |
条件化激活 | @ConditionalOnXxx 系列注解 |
存在DataSource.class 时加载数据源配置 |
可覆盖性 | @ConditionalOnMissingBean 预留扩展点 |
自定义DataSource Bean覆盖默认配置 |
模块化解耦 | Starter聚合依赖 + AutoConfigure模块 | spring-boot-starter-web 解耦Web层组件 |

二、实现原理
以下内容基于:Spring Boot 3.5.0
1. 启动入口:@SpringBootApplication
java
@SpringBootApplication // 复合注解
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration // 开启自动装配
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {...}
- 核心子注解 :
@EnableAutoConfiguration
: 触发自动配置流程。@ComponentScan
: 扫描当前包组件。@SpringBootConfiguration
: 标记配置类。
2. 自动配置核心:EnableAutoConfiguration
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) // 自动装配引入的核心类
public @interface EnableAutoConfiguration {...}
/**
* 自动装配入口
* 主要方法:getAutoConfigurationEntry
*/
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 1. 检查自动配置开关(默认true)
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 2. 加载AutoConfiguration.imports中的候选类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 3. 去重 + 排除(exclude属性或配置文件)
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 4. 条件过滤(@Conditional注解)
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,
getBeanClassLoader());
List<String> configurations = importCandidates.getCandidates();
Assert.state(!CollectionUtils.isEmpty(configurations),
"No auto configuration classes found in " + "META-INF/spring/"
+ this.autoConfigurationAnnotation.getName() + ".imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
}
AutoConfigurationImportSelector
工作流程:- 加载配置类 : 从
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
读取候选配置类(Spring Boot 2.7+迁移至此)。 - 过滤与排序 : 应用
@Conditional
条件 +@AutoConfigureOrder
排序。 - 注册Bean : 通过
ConfigurationClassPostProcessor
解析配置类。
- 加载配置类 : 从
3. 条件装配:@Conditional
的智能决策
以 DataSourceAutoConfiguration
核心代码逻辑为例:
java
@AutoConfiguration(before = SqlInitializationAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) // 依赖存在才生效
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class) // 绑定配置
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceCheckpointRestoreConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
@Bean
@ConditionalOnMissingBean(JdbcConnectionDetails.class)
PropertiesJdbcConnectionDetails jdbcConnectionDetails(DataSourceProperties properties) {
return new PropertiesJdbcConnectionDetails(properties);
}
}
}
abstract class DataSourceConfiguration {
/**
* Hikari DataSource configuration.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
@Bean
static HikariJdbcConnectionDetailsBeanPostProcessor jdbcConnectionDetailsHikariBeanPostProcessor(
ObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {
return new HikariJdbcConnectionDetailsBeanPostProcessor(connectionDetailsProvider);
}
@Bean
@ConfigurationProperties("spring.datasource.hikari")
HikariDataSource dataSource(DataSourceProperties properties, JdbcConnectionDetails connectionDetails,
Environment environment) {
String dataSourceClassName = environment.getProperty("spring.datasource.hikari.data-source-class-name");
HikariDataSource dataSource = createDataSource(connectionDetails, HikariDataSource.class,
properties.getClassLoader(), dataSourceClassName == null);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
}
- 关键条件注解 :
@ConditionalOnClass
: 类路径存在指定类时激活。@ConditionalOnProperty
: 配置属性匹配时激活。@ConditionalOnWebApplication
: Web环境时激活。
4. 配置绑定:@EnableConfigurationProperties
java
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {...}
yaml
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost/db
hikari:
maximum-pool-size: 20
- 动态注入原理 :
DataSourceProperties
通过@ConfigurationProperties
将YAML属性绑定到Java对象。
三、扩展机制:自定义配置覆盖默认行为
1. 切换为 Druid 连接池
yaml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 显式指定类型
需排除 HikariCP 依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
2. 完全禁用自动数据源配置
java
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class Application { ... }
适用场景:多数据源需手动配置时。
3. 覆盖默认配置的三种方式
方式 | 适用场景 | 示例 |
---|---|---|
排除自动配置类 | 禁用特定功能 | @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) |
自定义Bean覆盖 | 替换默认实现 | @Bean DataSource myDataSource() 替代HikariCP |
属性文件覆盖 | 调整参数 | spring.datasource.hikari.max-pool-size=30 |
四、架构级设计模式与高级特性
1、设计模式
1.1. 工厂方法模式(Factory Method)
应用场景 :动态创建 Bean 实例,解耦对象创建与使用。
源码示例 :DataSourceConfiguration
中的连接池工厂:
java
// org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration (Spring Boot 3.5.1)
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type",
havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
@Bean // 工厂方法:创建并配置 HikariCP 实例
@ConfigurationProperties("spring.datasource.hikari")
HikariDataSource dataSource(
DataSourceProperties properties,
JdbcConnectionDetails connectionDetails, // 新增:统一连接详情接口
Environment environment
) {
// 1. 获取数据源类名(支持高级配置)
String dataSourceClassName = environment.getProperty("spring.datasource.hikari.data-source-class-name");
// 2. 工厂方法创建实例
HikariDataSource dataSource = createDataSource(
connectionDetails,
HikariDataSource.class,
properties.getClassLoader(),
dataSourceClassName == null // 条件标志
);
// 3. 配置扩展属性
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName()); // 设置连接池名称
}
return dataSource;
}
// 工厂方法核心实现(protected 允许子类扩展)
protected <T> T createDataSource(
JdbcConnectionDetails connectionDetails,
Class<T> type,
ClassLoader classLoader,
boolean shouldDetermineClassName
) {
// 使用Builder模式创建实例
return DataSourceBuilder.create(classLoader)
.type(type) // 指定具体产品类型
.url(connectionDetails.getJdbcUrl()) // 使用统一连接详情
.username(connectionDetails.getUsername())
.password(connectionDetails.getPassword())
.driverClassName(connectionDetails.getDriverClassName())
.build();
}
}
设计意图:
- 通过
DataSourceBuilder
封装复杂构造逻辑,用户仅需指定类型(如HikariDataSource.class
)。 - 结合
@ConditionalOnClass
实现按需创建,避免无意义对象生成。
1.2. 策略模式(Strategy)
应用场景 :条件注解的动态决策机制。
源码示例 :OnClassCondition
的条件匹配策略:
java
// OnClassCondition (Spring Boot 3.5.1)
// 文件路径:OnClassCondition.java (Spring Boot 3.5.1)
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ClassLoader classLoader = context.getClassLoader();
ConditionMessage matchMessage = ConditionMessage.empty();
// 策略1:处理 @ConditionalOnClass 条件
List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
if (onClasses != null) {
// 使用策略类 ClassNameFilter.MISSING 过滤缺失类
List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
if (!missing.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class", "required classes")
.items(Style.QUOTE, missing); // 策略决策:不匹配
}
// 策略类 ClassNameFilter.PRESENT 验证存在类
matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
.found("required class", "required classes")
.items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));
}
// 策略2:处理 @ConditionalOnMissingClass 条件
List<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
if (onMissingClasses != null) {
// 使用策略类 ClassNameFilter.PRESENT 过滤存在类
List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);
if (!present.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class)
.found("unwanted class", "unwanted classes")
.items(Style.QUOTE, present)); // 策略决策:不匹配
}
// 策略类 ClassNameFilter.MISSING 验证缺失类
matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
.didNotFind("unwanted class", "unwanted classes")
.items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));
}
return ConditionOutcome.match(matchMessage); // 策略决策:匹配
}
// 解析条件注解中的类名
private List<String> getCandidates(AnnotatedTypeMetadata metadata, Class<?> annotationType) {
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(annotationType.getName(), true);
if (attributes == null) {
return null;
}
List<String> candidates = new ArrayList<>();
addAll(candidates, attributes.get("value"));
addAll(candidates, attributes.get("name"));
return candidates;
}
// 使用策略类过滤缺失类
//org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition#filter
protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter,
ClassLoader classLoader) {
if (CollectionUtils.isEmpty(classNames)) {
return Collections.emptyList();
}
List<String> matches = new ArrayList<>(classNames.size());
for (String candidate : classNames) {
if (classNameFilter.matches(candidate, classLoader)) {
matches.add(candidate);
}
}
return matches;
}
设计优势:
- 统一接口
Condition
抽象条件判断逻辑,支持扩展新条件类型(如@ConditionalOnCloudPlatform
)。 - 条件组合灵活,如
@ConditionalOnClass
+@ConditionalOnMissingBean
协同过滤。
1.3. 模板方法模式(Template Method)
核心作用 :定义算法骨架,允许子类重写特定步骤。
源码体现 (AutoConfigurationImportSelector
在2.2章节有更多篇幅的代码,此处就简写):
java
public class AutoConfigurationImportSelector implements DeferredImportSelector {
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata metadata) {
// 1. 模板方法:固定流程
List<String> candidates = getCandidateConfigurations(metadata); // 加载候选类
candidates = filter(candidates); // 条件过滤
return new AutoConfigurationEntry(candidates);
}
// 子类可重写的方法(扩展点)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata) {
return ImportCandidates.load(AutoConfiguration.class).getCandidates();
}
}
设计合理性分析:
- 流程标准化:固化"加载→过滤→注册"的装配流程,确保一致性。
- 可控扩展 :子类可重写
getCandidateConfigurations()
等方法(如自定义加载源)。
2、高级特性解析
2.1. 条件装配的元数据优化
核心作用 :通过预编译的元数据替代运行时反射,极大提升启动性能。
实现:
- 编译时元数据生成 :
- 在编译阶段,
spring-boot-autoconfigure-processor
注解处理器扫描所有自动配置类 - 提取条件注解(如
@ConditionalOnClass
)的元数据信息 - 生成
META-INF/spring-autoconfigure-metadata.properties
文件
- 在编译阶段,
- 运行时元数据加载:
java
// AutoConfigurationMetadataLoader
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
// 加载预编译的元数据文件
Properties properties = loader.loadMetadata(classLoader);
return new PropertiesAutoConfigurationMetadata(properties);
}
- 条件判断优化 :
- 直接使用预编译的元数据,避免反射扫描;
- 使用元数据中的条件判断结果
2.2. 延迟加载(Deferred Import)
核心作用 :通过DeferredImportSelector
接口实现配置类分组加载与拓扑排序,解决复杂依赖链问题(如 A 依赖 B,B 依赖 C)。
2.3. SPI 扩展机制升级
特性 :Spring Boot 3.0+ 重构了 SPI 扩展机制,弃用传统的 spring.factories
单文件模式 ,改用分层目录结构,提升加载灵活性和优先级控制。
源码适配:
- 自动配置类迁移至
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</font>
文件
java
// SpringFactoriesLoader (Spring Boot 3.5.1)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,
getBeanClassLoader());
List<String> configurations = importCandidates.getCandidates();
Assert.state(!CollectionUtils.isEmpty(configurations),
"No auto configuration classes found in " + "META-INF/spring/"
+ this.autoConfigurationAnnotation.getName() + ".imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
五、总结:设计演进与工程价值
自动装配引擎的设计本质:
"通过约定固化最佳实践,通过条件注解实现按需装配,通过模块化解耦技术栈集成,通过扩展点支持定制。"
- 约定优先 :
AutoConfiguration.imports
取代冗余配置声明。- 动态决策:条件注解在运行时解析环境(依赖、配置、Bean状态)。
- 可扩展性 :自定义
AutoConfigurationImportFilter
介入过滤流程。
设计模式:工厂方法、策略模式、模板方法构成核心骨架,平衡灵活性与复杂度。
高级特性:
- 条件装配元数据 → 编译期优化;
- 延迟加载 → 启动顺序控制;
- SPI 升级 → 可维护性提升。
演进方向:
- GraalVM 原生镜像:剥离反射,实现亚秒级启动;
- 动态策略引擎:支持运行时更新条件规则(参考 Groovy 脚本集成)。
Spring Boot 用 "智能约定 + 显式扩展" 将开发者从技术栈整合中解放,其模块化设计(Starter)、条件化装配(Conditional)、SPI 机制(FactoriesLoader)的组合,堪称框架设计的典范。