Spring Boot 自动配置原理深度解析
深入解析 Spring Boot 自动配置原理。内容包括约定优于配置优势、@SpringBootApplication 注解组合、@EnableAutoConfiguration 导入选择器机制、SpringFactoriesLoader 加载流程及 2.7+ 文件变化。详解条件注解控制生效逻辑,提供自定义 Starter 实现步骤与最佳实践,涵盖配置排除、启动报告查看及优先级设置,助力开发者掌握框架核心机制。

深入解析 Spring Boot 自动配置原理。内容包括约定优于配置优势、@SpringBootApplication 注解组合、@EnableAutoConfiguration 导入选择器机制、SpringFactoriesLoader 加载流程及 2.7+ 文件变化。详解条件注解控制生效逻辑,提供自定义 Starter 实现步骤与最佳实践,涵盖配置排除、启动报告查看及优先级设置,助力开发者掌握框架核心机制。

Spring Boot 的核心优势在于约定优于配置,它通过自动配置机制大幅简化了 Spring 应用的搭建和开发过程。
传统 Spring 开发需要大量 XML 配置或 Java Config:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("123456");
return new HikariDataSource(config);
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource());
return factory.getObject();
}
}
Spring Boot 只需引入依赖即可:
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
// 指定要扫描的包(默认当前包及其子包)
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)})
Class<?>[] exclude() default {};
// 指定自动配置要排除的类
String[] excludeName() default {};
// 指定扫描的包
String[] basePackages() default {};
}
| 注解 | 作用 |
|---|---|
@SpringBootConfiguration | 标识这是一个 Spring Boot 配置类,等价于 @Configuration |
@EnableAutoConfiguration | 启用自动配置机制 |
@ComponentScan | 组件扫描,默认扫描当前包及其子包中的 @Component |
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// 配置类名称,用于排除
String[] exclude() default {};
// 排除的配置类名称
String[] excludeName() default {};
// 配置类搜索路径
String[] value() default {};
}
@EnableAutoConfiguration 通过 @Import 导入 AutoConfigurationImportSelector,该类实现了 ImportSelector 接口:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 获取自动配置类
List<String> configurations = getAutoConfigurations(annotationMetadata);
// 排除用户已手动配置的类
configurations = removeDuplicates(configurations);
// 排除明确排除的类
Set<String> exclusions = getExclusions(annotationMetadata, configurations);
configurations.removeAll(exclusions);
// 过滤:检查条件注解是否满足
configurations = filter(configurations, autoConfigurationMetadata);
// 生成 @Import 需要的类名数组
String[] autoConfigurations = configurations.toArray(new String[0]);
// 触发 AutoConfigurationImportEvent 事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return autoConfigurations;
}
}
@SpringBootApplication 启动@EnableAutoConfigurationAutoConfigurationImportSelector.selectImportsSpringFactoriesLoader.loadFactoryNamesMETA-INF/spring.factories 或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsSpring Boot 2.7 之前使用 META-INF/spring.factories:
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
Spring Boot 2.7+ 推荐使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (每行一个)
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
Spring Boot 3.x 完全移除了 spring.factories,只支持 AutoConfiguration.imports 文件。
public abstract class SpringFactoriesLoader {
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
// factoryType = EnableAutoConfiguration.class
String factoryTypeName = factoryType.getName();
// 从 classpath 加载所有 META-INF/spring.factories
// 并解析为 Properties
Map<String, List<String>> result = loadSpringFactories(classLoader);
return result.getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 缓存
if (cache.containsKey(classLoader)) {
return cache.get(classLoader);
}
// 加载所有 spring.factories 文件
Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
// 解析 Properties
Properties properties = PropertiesLoaderUtils.loadProperties(url);
// 合并到 result
result.addAll(properties);
}
cache.put(classLoader, result);
return result;
}
}
Spring Boot 使用条件注解控制配置类的生效条件。
| 注解 | 作用 |
|---|---|
@ConditionalOnClass | 当 classpath 存在指定类时生效 |
@ConditionalOnMissingClass | 当 classpath 不存在指定类时生效 |
@ConditionalOnBean | 当容器中存在指定 Bean 时生效 |
@ConditionalOnMissingBean | 当容器中不存在指定 Bean 时生效 |
@ConditionalOnProperty | 当配置属性满足条件时生效 |
@ConditionalOnResource | 当资源存在时生效 |
@ConditionalOnWebApplication | 当是 Web 应用时生效 |
// 只有存在 Druid 数据源时才配置
@ConditionalOnClass(DruidDataSource.class)
@Configuration
public class DruidConfig {
@ConditionalOnMissingBean(DataSource.class)
@Bean
public DataSource dataSource() {
return new DruidDataSource();
}
}
// 只有配置了 spring.redis.host 时才配置
@ConditionalOnProperty(prefix = "spring.redis", name = "host")
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
return new RedisTemplate<>(connectionFactory);
}
}
// 只有在 Web 应用中才配置
@ConditionalOnWebApplication
@Configuration
public class WebMvcConfig {
// Web 相关配置
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
@Conditional 是 Spring 4.0 引入的通用条件注解,OnClassCondition 是其具体实现:
@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition implements ConfigurationCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取 @ConditionalOnClass 注解的属性
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(ConditionalOnClass.class.getName());
List<Object> classesToCheck = attributes.get("value");
// 检查 classpath 是否存在这些类
for (Object classToCheck : classesToCheck) {
if (!ClassUtils.isPresent(classToCheck.toString(), context.getClassLoader())) {
// 不存在,返回不匹配
return ConditionOutcome.noMatch("@ConditionalOnClass " + classToCheck + " not present");
}
}
return ConditionOutcome.match();
}
}
SpringApplication.main()createApplicationContext()refresh(context)invokeBeanFactoryPostProcessors()@Configuration 类的 @BeanSpring Boot 的自动配置类本质上是一个 @Configuration 类:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EmbeddedServletContainer.class)
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class WebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(TomcatServletWebServerFactory.class)
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
| 类型 | 命名规范 | 示例 |
|---|---|---|
| 官方 Starter | spring-boot-starter-* | spring-boot-starter-web |
| 第三方 Starter | *-spring-boot-starter | druid-spring-boot-starter |
第一步:创建自动配置类
@Configuration
@ConditionalOnProperty(prefix = "myapp", name = "enabled", havingValue = "true", matchIfMissing = true)
public class MyAppAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() {
return new MyService();
}
}
第二步:创建 spring.factories 或 imports 文件
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.myapp.MyAppAutoConfiguration
或
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.myapp.MyAppAutoConfiguration
第三步:创建配置属性类
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private String name = "default";
private int timeout = 3000;
// getters and setters
}
第四步:在启动类启用
@SpringBootApplication
@EnableConfigurationProperties(MyAppProperties.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
# application.yml
myapp:
enabled: true
name: my-app
timeout: 5000
@RestController
public class TestController {
@Autowired
private MyService myService;
@GetMapping("/test")
public String test() {
return myService.sayHello();
}
}
@SpringBootApplication@EnableAutoConfigurationAutoConfigurationImportSelectorSpringFactoriesLoaderMETA-INF/spring.factories / META-INF/spring/xxx.imports@Conditional 条件过滤// AbstractApplicationContext.refresh()
public void refresh() {
// ...
// 7. 初始化 BeanFactory 扩展
invokeBeanFactoryPostProcessors(beanFactory);
// ...
// 11. 初始化所有单例 Bean
finishBeanFactoryInitialization(beanFactory);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(DataSourceAutoConfiguration.PooledDataSourceCondition.class)
@ConditionalOnMissingBean({DataSource.class, XADataSource.class})
@Import(DataSourceConfiguration.Hikari.class)
protected static class Hikari {
// 配置 HikariCP 连接池
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置序列化器
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@ConditionalOnClass({WebMvcConfigurer.class})
@EnableConfigurationProperties({WebMvcProperties.class})
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// 配置请求映射
}
}
// 方式 1:启动类排除
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, RedisAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
# 方式 2:application.yml 排除
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
# 启用 debug 模式
java -jar app.jar --debug
或 application.yml:
spring:
main:
log-startup-info: true
输出类似:
========================= AUTO-CONFIGURATION REPORT =========================
Positive matches:
-----------------
DataSourceAutoConfiguration - @ConditionalOnClass found on class 'javax.sql.DataSource' (OnClassCondition)
- @ConditionalOnMissingBean (types: javax.sql.DataSource;SearchStrategy: all) did not find any beans (OnBeanCondition)
Negative matches:
-----------------
RedisAutoConfiguration - @ConditionalOnClass did not find 'org.springframework.data.redis.core.RedisOperations' (OnClassCondition)
application.yml 中配置application.yml 未配置时使用Spring Boot 自动配置是其核心优势,理解其原理对面试和开发都非常重要。
@Configuration、@EnableAutoConfiguration、@ComponentScan 三个注解SpringFactoriesLoader 加载 META-INF/spring.factories 或 AutoConfiguration.imports 文件@ConditionalOnClass、@ConditionalOnBean 等)控制配置类的生效条件@Configuration 的普通 Spring 配置类掌握这些知识点,能够帮助你更好地理解 Spring Boot 的工作原理,也能够自定义 Starter 封装公共组件。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online