Spring Boot 自动装配的核心是 "约定大于配置":通过@EnableAutoConfiguration触发,加载spring.factories中的自动配置类,结合条件注解动态注入 Bean;
自定义 Starter 则是遵循该机制,封装核心功能 + 配置属性 + 自动配置类,实现 "引入即生效" 的开箱即用能力。

一、Spring Boot 自动装配梳理
Spring Boot 自动装配
├─ 1. 注解驱动入口
│ ├─ @SpringBootApplication(复合注解)
│ │ ├─ @SpringBootConfiguration(本质@Configuration)
│ │ ├─ @EnableAutoConfiguration(自动装配核心)
│ │ └─ @ComponentScan(组件扫描范围)
│ └─ 启动类入口
│ └─ SpringApplication.run(启动类.class, args)(触发装配)
├─ 2. 自动装配核心机制
│ ├─ @EnableAutoConfiguration 作用
│ │ ├─ 导入 AutoConfigurationImportSelector 类
│ │ └─ 触发Spring扫描自动配置类
│ └─ AutoConfigurationImportSelector 核心特性
│ ├─ 实现 DeferredImportSelector 接口(延迟导入)
│ └─ 重写 selectImports() 方法(核心入口)
├─ 3. 配置类选择过程
│ ├─ selectImports() 方法逻辑
│ │ └─ 调用 getAutoConfigurationEntry() 获取配置项
│ └─ getAutoConfigurationEntry() 核心步骤
│ ├─ 加载候选配置类(从spring.factories读取)
│ ├─ 去重处理(避免重复配置)
│ ├─ 条件过滤(基于@Conditional家族注解)
│ └─ 排除指定配置(spring.autoconfigure.exclude)
├─ 4. spring.factories 加载机制
│ ├─ SpringFactoriesLoader 工具类
│ │ ├─ 扫描所有Jar包的 META-INF/spring.factories
│ │ ├─ 读取 EnableAutoConfiguration 对应的配置类列表
│ │ └─ 合并多个Jar包中的配置(去重)
│ └─ spring.factories 配置格式
│ └─ 键值对:org.springframework.boot.autoconfigure.EnableAutoConfiguration=配置类全限定名(多个用逗号分隔)
├─ 5. 条件过滤机制(配置类生效规则)
│ ├─ @Conditional 注解家族(核心过滤逻辑)
│ │ ├─ @ConditionalOnClass:类路径存在指定类时生效
│ │ ├─ @ConditionalOnMissingClass:类路径不存在指定类时生效
│ │ ├─ @ConditionalOnBean:容器中存在指定Bean时生效
│ │ ├─ @ConditionalOnMissingBean:容器中不存在指定Bean时生效
│ │ ├─ @ConditionalOnProperty:配置文件存在指定属性时生效
│ │ └─ @ConditionalOnWebApplication:Web环境下生效
│ └─ 条件评估器
│ └─ ConditionEvaluator(Spring内部评估条件是否满足)
└─ 6. Bean注册与应用启动
├─ 配置类解析
│ └─ ConfigurationClassParser(解析@Configuration类)
├─ Bean定义注册
│ └─ BeanDefinitionRegistry(将配置类中的Bean注册到容器)
└─ 应用启动完成
└─ ApplicationContext 初始化完成(Bean实例化、依赖注入完成)
二、Spring Boot 自动装配加载过程分析
1. 自动装配入口:@SpringBootApplication
@SpringBootApplication 是 Spring Boot 应用的核心注解,它是一个组合注解,包含了三个关键注解:
java
@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 是自动装配的核心入口点。
2. 自动装配核心:@EnableAutoConfiguration
@EnableAutoConfiguration 注解通过 @Import 引入了 AutoConfigurationImportSelector:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// ...
}
@Import(AutoConfigurationImportSelector.class) 是自动装配的关键,它会导入所有符合条件的自动配置类。
3. 配置类选择器:AutoConfigurationImportSelector
AutoConfigurationImportSelector 实现了 ImportSelector 接口,其核心方法是 selectImports():
java
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
该方法会调用 getAutoConfigurationEntry() 来获取需要导入的自动配置类。
4. 获取自动配置条目:getAutoConfigurationEntry
getAutoConfigurationEntry() 方法是获取自动配置类的核心:
java
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 1. 加载所有候选配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 2. 去重
configurations = removeDuplicates(configurations);
// 3. 应用排除规则
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 4. 应用过滤规则
configurations = getConfigurationClassFilter().filter(configurations);
// 5. 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
5. 加载候选配置类:getCandidateConfigurations
getCandidateConfigurations() 方法通过 SpringFactoriesLoader 加载 spring.factories 文件中的配置类:
java
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. "
+ "If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
6. SpringFactoriesLoader 加载机制
SpringFactoriesLoader 是 Spring 框架用于加载工厂类的工具,它会从所有 JAR 包的 META-INF/spring.factories 文件中读取配置:
java
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 缓存机制,避免重复加载
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 加载所有 META-INF/spring.factories 文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
其中,FACTORIES_RESOURCE_LOCATION 常量定义为 META-INF/spring.factories。
7. 条件过滤机制
加载到候选配置类后,Spring Boot 会应用条件注解进行过滤,常用的条件注解包括:
@ConditionalOnClass:当类路径存在指定类时生效@ConditionalOnMissingClass:当类路径不存在指定类时生效@ConditionalOnBean:当容器中存在指定 Bean 时生效@ConditionalOnMissingBean:当容器中不存在指定 Bean 时生效@ConditionalOnProperty:当配置属性满足指定条件时生效@ConditionalOnWebApplication:当应用是 Web 应用时生效@ConditionalOnNotWebApplication:当应用不是 Web 应用时生效
8. Bean 注册过程
经过条件过滤后,符合条件的配置类会被注册到 Spring 容器中,这些配置类通常会使用 @Bean 注解定义各种 Bean。
9. 应用启动完成
当所有自动配置类都被处理完成后,Spring Boot 应用就启动完成了,所有配置的 Bean 都已经注册到容器中。
总结
Spring Boot 自动装配的完整过程可以总结为:
@SpringBootApplication组合注解启动应用@EnableAutoConfiguration启用自动装配@Import(AutoConfigurationImportSelector)导入配置选择器AutoConfigurationImportSelector.selectImports()选择需要导入的配置类SpringFactoriesLoader.loadFactoryNames()加载spring.factories中的配置类- 应用去重、排除和条件过滤
- 注册符合条件的配置类和 Bean
- 应用启动完成
三、配置校验 Starter 使用示例
1. 示例项目说明
本示例展示如何在 Spring Boot 项目中使用配置校验 Starter。
2. 项目结构
config-validator-demo/
├── src/main/java/com/example/demo/
│ └── DemoApplication.java # 主应用类
├── src/main/resources/
│ └── application.properties # 配置文件
└── pom.xml # 项目依赖配置
3. 添加依赖
在 pom.xml 文件中添加配置校验 Starter 依赖:
xml
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 配置校验 Starter -->
<dependency>
<groupId>com.example</groupId>
<artifactId>config-validator-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
4. 主应用类
java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
5. 配置文件示例
5.1 正确的配置 (application.properties)
properties
# 服务器配置
server.port=8080
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=password
# 配置校验配置
config.validator.enabled=true
config.validator.fail-fast=true
config.validator.required-properties=spring.datasource.url,spring.datasource.username,spring.datasource.password
config.validator.ignored-properties=spring.datasource.driver-class-name
5.2 错误的配置 (application.properties)
properties
# 服务器配置
server.port=99999 # 无效的端口号
# 数据库配置
spring.datasource.url=invalid-url # 无效的数据库URL
# spring.datasource.username # 缺少必需的配置
spring.datasource.password=password
# 配置校验配置
config.validator.enabled=true
config.validator.fail-fast=true
config.validator.required-properties=spring.datasource.url,spring.datasource.username,spring.datasource.password
6. 运行效果
6.1 配置正确时的输出
=================== 配置校验成功 ===================
所有必需的配置属性都已正确配置!
================================================
6.2 配置错误时的输出
=================== 配置校验失败 ===================
ERROR: server.port - 端口号必须是0-65535之间的整数
ERROR: spring.datasource.url - 数据库URL格式不正确
ERROR: spring.datasource.username - 配置属性必须存在且不为空
================================================
7. 测试端点
可以添加一个测试端点来验证配置是否生效:
java
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Autowired
private Environment environment;
@GetMapping("/config")
public String getConfig() {
String port = environment.getProperty("server.port");
String dbUrl = environment.getProperty("spring.datasource.url");
return String.format("Server Port: %s, Database URL: %s", port, dbUrl);
}
}
8. 快速失败模式测试
- 在配置文件中设置
config.validator.fail-fast=true - 故意遗漏一个必需的配置属性
- 启动应用,应用应该会在启动时抛出异常并终止
9. 忽略属性测试
- 在配置文件中设置
config.validator.ignored-properties=spring.datasource.username - 故意遗漏
spring.datasource.username配置 - 启动应用,应用应该会正常启动,不会因为缺少该配置而失败
10. 禁用配置校验
在配置文件中设置 config.validator.enabled=false 可以禁用配置校验功能。
四、相关资源
- Spring Boot 官方文档:https://spring.io/projects/spring-boot
- Spring Boot 自动装配官方指南:https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application