
Spring Boot的自动配置就是自动帮你把代码(依赖)变成对象(Bean)。
Spring Boot自动配置原理
我直接用一个真实的例子带你一步步看Spring Boot的自动配置是怎么工作的!
场景重现:你要创建一个Web项目
第一步:创建项目
xml
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
第二步:启动类
java
@SpringBootApplication // 🔑 关键魔法开始的地方!
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
🧭 自动配置执行流程详解
阶段1:启动扫描
当你运行 SpringApplication.run() 时:
java
// SpringBoot内部代码(简化版)
public class SpringApplication {
public static void run(Class<?> primarySource, String... args) {
// 1. 创建应用上下文
ApplicationContext context = createApplicationContext();
// 2. 加载配置类
load(context, primarySource);
// 3. 🔍 关键步骤:调用@SpringBootApplication注解的组件
}
}
阶段2:解析@SpringBootApplication
java
// @SpringBootApplication 内部结构
@SpringBootConfiguration // 告诉Spring:这是配置类
@EnableAutoConfiguration // 🔑 启动自动配置的关键!
@ComponentScan // 扫描当前包下的组件
public @interface SpringBootApplication {
// 这就是那个神奇的注解
}
阶段3:@EnableAutoConfiguration 的魔法
java
// @EnableAutoConfiguration 的定义
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) // 🔑 关键导入!
public @interface EnableAutoConfiguration {
// 它导入了"自动配置选择器"
}
🔍 核心组件:AutoConfigurationImportSelector
AutoConfigurationImportSelector 是 Spring Boot 自动配置的核心,它主要做以下三件大事:
- 扫描并加载所有候选的自动配置类
从哪里加载:从 classpath 下所有的 META-INF/spring.factories 文件(META-INF/spring.factories 文件是从依赖中来的。具体来说,它是打包在JAR文件中的)中加载 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的配置类。
结果:得到一个包含所有自动配置类的列表(可能有100多个)。
- 过滤和去重
根据条件注解过滤:根据类路径下的依赖(即有哪些类存在)、配置文件中的设置以及当前容器的状态(例如已有哪些Bean)来过滤掉不需要的自动配置类。
去重:确保相同的配置类不会重复加载。
排序:按照一定的顺序(例如使用 @AutoConfigureAfter、@AutoConfigureBefore 等注解定义的顺序)对自动配置类进行排序。
- 返回最终需要生效的自动配置类
将过滤和排序后的自动配置类列表返回给 Spring 容器,Spring 容器会将这些类注册为 Bean 定义,随后实例化并配置相应的 Bean。
详细过程:
扫描 spring.factories 文件:
Spring Boot 在启动时会调用 AutoConfigurationImportSelector 的 selectImports 方法。
该方法内部会使用 SpringFactoriesLoader 工具类,从 classpath 中搜索所有 META-INF/spring.factories 配置文件,并读取其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置类列表。
条件过滤:
加载的配置类并不是全部都会生效,每个自动配置类上都有很多条件注解(如 @ConditionalOnClass、@ConditionalOnBean、@ConditionalOnProperty 等)。
Spring Boot 会利用条件注解进行过滤,只有满足所有条件的自动配置类才会被最终使用。
去重和排序:
去除重复的配置类(可能多个 jar 包都提供了相同的自动配置类)。
按照一定的顺序排序,确保配置的加载顺序符合要求。
返回数组:
最终返回一个字符串数组,里面是过滤后需要加载的自动配置类的全限定名。
示例代码片段(简化):
java
public class AutoConfigurationImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 获取所有自动配置类(从spring.factories)
List<String> configurations = getCandidateConfigurations();
// 2. 去重
configurations = removeDuplicates(configurations);
// 3. 根据条件注解过滤
configurations = filter(configurations, autoConfigurationMetadata);
// 4. 排序
configurations = sort(configurations);
// 5. 返回数组
return configurations.toArray(new String[0]);
}
}
比喻:
第一步:就像你去图书馆,按照索引(spring.factories)找到所有可能相关的书(自动配置类)。
第二步:你根据这些书的目录(条件注解)判断哪些书是你当前需要的(过滤)。
第三步:你把选中的书按照一定的顺序(排序)放好,然后借回家(加载到容器)。
通过这三步,Spring Boot 就能够智能地根据项目的依赖和配置,自动加载所需的配置类,从而完成自动配置。
这是自动配置的大脑,它做了三件大事:
1. 加载所有候选配置
java
public class AutoConfigurationImportSelector {
// 这个方法会被Spring调用
public String[] selectImports(AnnotationMetadata metadata) {
// 1. 从所有jar包中读取 META-INF/spring.factories 文件
List<String> configurations = getCandidateConfigurations();
// 2. 去重和过滤
configurations = removeDuplicates(configurations);
configurations = sort(configurations);
// 3. 返回所有自动配置类的全限定名
return configurations.toArray(new String[0]);
}
// 加载配置
protected List<String> getCandidateConfigurations() {
// 读取这个文件:META-INF/spring.factories
List<String> configurations =
SpringFactoriesLoader.loadFactoryNames(
EnableAutoConfiguration.class,
getBeanClassLoader()
);
return configurations;
}
}
2. 读取配置文件
在 spring-boot-autoconfigure-2.7.0.jar 中:
META-INF/spring.factories 文件内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
... 共有100多个自动配置类!
🎯 条件判断:智能选择
Spring Boot不是把所有100多个配置都加载,而是智能筛选:
以WebMvcAutoConfiguration为例
java
@Configuration(proxyBeanMethods = false)
// 🔍 关键条件判断:
@ConditionalOnWebApplication(type = Type.SERVLET) // 必须是Web应用
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) // 用户没有自己配
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
public class WebMvcAutoConfiguration {
// 只有满足上述所有条件,这个配置类才生效!
}
实际判断逻辑:
java
// 伪代码:Spring Boot内部的条件判断
if (有Servlet相关类 in classpath &&
是Web应用 &&
用户没有自定义WebMvc配置) {
// 加载WebMvcAutoConfiguration
加载这个类并创建Bean();
}
🏗️ 自动创建Bean
自动配置类内部:
java
@Configuration
public class WebMvcAutoConfiguration {
// 1. 定义ViewResolver Bean
@Bean
@ConditionalOnMissingBean // 如果用户没定义,我才创建
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
// 2. 定义MessageConverter Bean
@Bean
@ConditionalOnMissingBean
public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
return new MappingJackson2HttpMessageConverter();
}
// 3. 配置静态资源
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
}
📊 完整流程图
1. 启动应用
↓
2. 扫描@SpringBootApplication
↓
3. 发现@EnableAutoConfiguration
↓
4. 加载AutoConfigurationImportSelector
↓
5. 读取所有META-INF/spring.factories文件
↓
6. 收集100+个自动配置类
↓
7. 过滤(基于条件注解)←---→ 条件评估
↓
8. 剩下20个符合条件的配置类
↓
9. 加载这些配置类
↓
10. 执行@Bean方法
↓
11. 创建Bean放入Spring容器
↓
12. 应用启动完成,可以直接使用!
🎪 形象比喻
Spring Boot自动配置就像一个"智能管家":
- 你: "我要做Web开发"(加
spring-boot-starter-web依赖) - 管家: 收到!检查一下...
- ✅ 有
Servlet.class在类路径(Web环境) - ✅ 有
DispatcherServlet.class(Spring MVC) - ❌ 用户没有自定义Web配置
- ✅ 当前是SERVLET类型Web应用
- ✅ 有
- 管家: 所有条件满足,开始工作!
- 🏗️ 安装Tomcat服务器
- 🏗️ 配置Spring MVC
- 🏗️ 设置JSON转换器
- 🏗️ 配置静态资源路径
- 你: "我还需要数据库"
- 管家: 检查...
- ✅ 有
DataSource.class(加了数据库驱动) - ✅ 有
spring.datasource.url配置 - ❌ 用户没有自定义DataSource
- ✅ 有
- 管家: 开始配置数据库!
- 🏗️ 创建DataSource连接池
- 🏗️ 配置连接参数
- 🏗️ 设置事务管理器
🔧 源码跟踪示例
如果你想亲眼看看自动配置是怎么工作的,可以这样:
java
// 1. 在application.properties中开启debug
debug=true
// 2. 启动应用,查看控制台日志
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches: // 匹配成功的
-----------------
WebMvcAutoConfiguration matched:
- @ConditionalOnClass found required classes
'javax.servlet.Servlet', 'org.springframework.web.servlet.DispatcherServlet'
- found 'session' scope (OnWebApplicationCondition)
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes
'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'
- @ConditionalOnProperty (spring.datasource.type) matched
Negative matches: // 匹配失败的
-----------------
RabbitAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class
'com.rabbitmq.client.ConnectionFactory'
RedisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class
'org.springframework.data.redis.core.RedisOperations'
🎯 核心原理总结
Spring Boot自动配置的核心是:
- 通过依赖推断需求(看你classpath有什么)
- 通过条件注解智能判断(@ConditionalOnXxx)
- 按默认最佳实践创建Bean(遵循约定大于配置)
- 允许用户轻松覆盖(@Bean或配置文件)
💡 一句话理解
Spring Boot自动配置 = "条件装配" + "约定优先" + "零配置开箱即用"
它就像一个懂你的助手:
- 看你带了什么工具(依赖)
- 猜你要做什么事(条件判断)
- 按最常用的方式帮你准备好(自动配置)
- 但你随时可以自己动手(自定义配置)
这样既能让新手快速上手,又能让老手灵活定制!