作为 Java 后端开发者,我们每天都在享受 Spring Boot 带来的便利:引入一个spring-boot-starter-web依赖,就能直接写 Controller 接收 HTTP 请求;引入spring-boot-starter-data-redis,就能直接操作 Redis。不需要任何 XML 配置,不需要手动注册 Bean,一切都自动完成了。
但很多人用了很多年 Spring Boot,却始终没有搞懂一个最核心的问题:为什么引入一个 starter 就能自动配置好所有东西?Spring Boot 是怎么知道我需要哪些 Bean 的?
这就是 Spring Boot 的核心魔法 ------自动装配。它不仅是 Spring Boot 最成功的特性,也是面试中 100% 会被深挖的考点:
- Spring Boot 自动装配的底层原理是什么?
@EnableAutoConfiguration注解到底做了什么?- Spring Boot 3.x 为什么废弃了
spring.factories? - 如何自定义一个自动配置类?
- 如何开发一个属于自己的 Spring Boot Starter?
这篇文章,我们就从核心原理→执行流程→自定义自动配置→自定义 Starter 实战四个维度,彻底搞懂 Spring Boot 自动装配。不仅会讲清楚理论,更会提供可直接落地的代码示例和最佳实践,让你看完既能轻松应对面试,又能在实际项目中封装自己的通用组件。

一、先搞懂:什么是自动装配?
自动装配,简单来说就是Spring Boot 根据我们引入的依赖,自动将需要的 Bean 注册到 Spring 容器中。我们不需要手动编写任何配置代码,只需要引入对应的 starter 依赖,Spring Boot 就会自动完成所有的配置工作。
举个最经典的例子:当我们在项目中引入spring-boot-starter-web依赖后,Spring Boot 会自动做以下事情:
- 自动配置
DispatcherServlet - 自动配置
Tomcat容器 - 自动配置
RequestMappingHandlerMapping和RequestMappingHandlerAdapter - 自动配置
HttpMessageConverter - 自动配置静态资源映射
- 等等...
所有这些配置,在传统的 Spring MVC 中需要我们手动编写大量的 XML 或 Java 配置,但在 Spring Boot 中,只需要引入一个依赖就全部搞定了。这就是自动装配的威力。
自动装配的核心思想
自动装配的核心思想是约定大于配置(Convention over Configuration)。Spring Boot 制定了一套默认的约定:
- 默认的配置文件是
application.yml或application.properties - 默认的包扫描路径是主启动类所在的包及其子包
- 默认的 Web 容器是 Tomcat
- 默认的端口是 8080
- 等等...
只要我们遵循这些约定,Spring Boot 就能自动完成大部分配置工作。只有当我们需要修改默认配置时,才需要在配置文件中进行修改。这大大减少了配置代码,提高了开发效率。
二、自动装配的核心原理
Spring Boot 自动装配的核心是 **@EnableAutoConfiguration** 注解。这个注解开启了自动装配功能,是整个自动装配机制的入口。
1. @EnableAutoConfiguration 注解
我们先来看一下@SpringBootApplication注解的定义:
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 {
// ...
}
可以看到,@SpringBootApplication是一个组合注解,它包含了三个核心注解:
@SpringBootConfiguration:标记这是一个 Spring Boot 配置类@EnableAutoConfiguration:开启自动装配功能@ComponentScan:开启组件扫描
其中,@EnableAutoConfiguration是最关键的注解,它通过@Import注解导入了AutoConfigurationImportSelector类,这个类负责加载所有的自动配置类。
2. 重要更新:Spring Boot 3.x 废弃了 spring.factories
非常重要的一点 :spring.factories是 Spring Boot 2.x 及更早版本的 SPI 配置方式。从Spring Boot 2.7 开始,官方已经将其标记为废弃;从Spring Boot 3.0 开始,已经完全移除了对spring.factories中自动配置项的支持,改用了全新的配置方式。
新旧配置方式对比
| 特性 | Spring Boot 2.x | Spring Boot 3.x |
|---|---|---|
| 配置文件 | META-INF/spring.factories |
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |
| 文件格式 | 键值对形式 | 纯类名列表,每行一个 |
| 加载器 | SpringFactoriesLoader |
ImportCandidates |
| 模块化支持 | ❌ | ✅ |
| GraalVM 支持 | ❌ | ✅ |
| 性能 | 较低 | 较高 |
为什么要废弃 spring.factories?
Spring Boot 官方废弃 spring.factories 主要有以下几个原因:
- 性能优化:新的 imports 文件机制是静态加载,不需要运行时扫描所有 jar 包,启动速度更快
- 模块化支持:与 Java 9 + 的模块系统(module-info.java)兼容性更好
- 类型安全:IDE 可以直接校验类名的正确性,支持自动补全和导航
- GraalVM 原生支持:新机制支持 AOT 提前编译,是 Spring Boot 3.x 原生镜像支持的基础
- 结构更清晰:每个扩展点有自己独立的配置文件,不再是所有配置都挤在一个 spring.factories 文件中
3. 自动装配的完整执行流程
Spring Boot 自动装配的完整执行流程可以分为以下 7 个步骤:
- 应用启动 :执行
SpringApplication.run()方法,启动 Spring Boot 应用 - 加载主配置类 :解析主启动类上的
@SpringBootApplication注解 - 开启自动装配 :
@EnableAutoConfiguration注解导入AutoConfigurationImportSelector类 - 加载自动配置类 :
AutoConfigurationImportSelector从配置文件中加载所有的自动配置类- Spring Boot 2.x:从
META-INF/spring.factories文件中加载 - Spring Boot 3.x:从
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中加载
- Spring Boot 2.x:从
- 条件过滤 :根据条件注解(
@Conditional系列注解)过滤掉不符合条件的自动配置类 - 注册 Bean:将符合条件的自动配置类中的 Bean 注册到 Spring 容器中
- 完成装配:Spring 容器自动完成这些 Bean 的实例化、依赖注入和初始化,应用启动完成

4. 自动装配的灵魂:条件注解
条件注解是自动装配的灵魂,它允许我们根据特定的条件来决定是否注册一个 Bean。Spring Boot 提供了大量的条件注解,常用的有:
| 注解 | 作用 |
|---|---|
@ConditionalOnClass |
当类路径下存在指定的类时,注册 Bean |
@ConditionalOnMissingClass |
当类路径下不存在指定的类时,注册 Bean |
@ConditionalOnBean |
当容器中存在指定的 Bean 时,注册 Bean |
@ConditionalOnMissingBean |
当容器中不存在指定的 Bean 时,注册 Bean |
@ConditionalOnProperty |
当配置文件中存在指定的属性时,注册 Bean |
@ConditionalOnResource |
当类路径下存在指定的资源时,注册 Bean |
@ConditionalOnWebApplication |
当是 Web 应用时,注册 Bean |
@ConditionalOnNotWebApplication |
当不是 Web 应用时,注册 Bean |
@ConditionalOnJava |
当 Java 版本符合要求时,注册 Bean |
这些条件注解可以组合使用,实现非常灵活的条件判断。例如,@ConditionalOnClass + @ConditionalOnMissingBean的组合,就是 "当类路径下存在某个类,并且容器中没有对应的 Bean 时,才注册这个 Bean",这是自动配置中最常用的组合。
三、实战一:自定义自动配置类
理解了自动装配的原理,我们先来实战一下,自定义一个简单的自动配置类。
我们要实现的功能是:当类路径下存在HelloService类时,自动将HelloService注册到 Spring 容器中,并且可以通过配置文件自定义问候语。
步骤 1:创建 Maven 项目
创建一个普通的 Maven 项目,引入 Spring Boot 的依赖:
XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>3.2.5</version>
<optional>true</optional>
</dependency>
</dependencies>
步骤 2:编写配置属性类
创建HelloProperties类,用于绑定配置文件中的属性:
java
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
/**
* 问候语,默认值为"Hello, World!"
*/
private String message = "Hello, World!";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
@ConfigurationProperties注解会将配置文件中以hello为前缀的属性绑定到这个类的字段上。
步骤 3:编写服务类
创建HelloService类,这是我们要自动注册的 Bean:
java
public class HelloService {
private final HelloProperties helloProperties;
// 使用构造方法注入配置属性
public HelloService(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
public String sayHello(String name) {
return helloProperties.getMessage() + " " + name;
}
}
步骤 4:编写自动配置类
创建HelloAutoConfiguration类,这是自动配置的核心类:
java
// Spring Boot 3.x推荐使用@AutoConfiguration替代@Configuration
@AutoConfiguration
// 当类路径下存在HelloService类时,才启用这个自动配置
@ConditionalOnClass(HelloService.class)
// 启用HelloProperties的配置绑定
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
// 当容器中不存在HelloService Bean时,才注册这个Bean
@Bean
@ConditionalOnMissingBean
public HelloService helloService(HelloProperties helloProperties) {
return new HelloService(helloProperties);
}
}
步骤 5:配置自动配置类
这是新旧版本差异最大的地方。
Spring Boot 3.x 版本
在src/main/resources/META-INF/spring目录下创建org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,内容为自动配置类的全限定名:
com.example.hello.HelloAutoConfiguration
Spring Boot 2.x 版本
在src/main/resources/META-INF目录下创建spring.factories文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.hello.HelloAutoConfiguration
步骤 6:打包安装
执行mvn install命令,将项目安装到本地 Maven 仓库。
步骤 7:测试自动配置
创建一个 Spring Boot 项目,引入我们刚才打包的依赖:
XML
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-autoconfigure</artifactId>
<version>1.0.0</version>
</dependency>
在application.yml中配置问候语:
bash
hello:
message: "你好"
编写测试类:
java
@SpringBootTest
public class HelloTest {
@Autowired(required = false)
private HelloService helloService;
@Test
public void testSayHello() {
if (helloService != null) {
String result = helloService.sayHello("Spring Boot");
System.out.println(result); // 输出:你好 Spring Boot
} else {
System.out.println("HelloService没有被自动注册");
}
}
}
运行测试,成功输出结果,说明我们的自定义自动配置已经生效了!
四、实战二:自定义 Spring Boot Starter
刚才我们实现了一个简单的自动配置类,但在实际项目中,我们通常会将自动配置和相关依赖打包成一个 Starter,方便其他项目使用。
1. 什么是 Spring Boot Starter?
Spring Boot Starter 本质上是一个依赖描述符,它包含了一组相关的依赖和自动配置类。当我们引入一个 Starter 时,它会自动引入所有需要的依赖,并且自动完成配置。
一个完整的 Spring Boot Starter 通常包含两个部分:
- autoconfigure 模块:包含自动配置类、配置属性类等
- starter 模块:只包含 pom.xml,用于引入 autoconfigure 模块和相关依赖
这种分离的设计可以让自动配置和依赖管理分开,更加灵活。
2. 自定义 Starter 的命名规范
Spring 官方的 Starter 命名格式是spring-boot-starter-xxx,比如spring-boot-starter-web、spring-boot-starter-data-redis。
第三方自定义的 Starter 命名格式是xxx-spring-boot-starter,比如mybatis-spring-boot-starter、druid-spring-boot-starter。
我们要实现的 Starter 命名为hello-spring-boot-starter。
3. 项目结构
我们的项目结构如下:
hello-spring-boot-starter
├── hello-spring-boot-autoconfigure
│ ├── src
│ │ ├── main
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── hello
│ │ │ │ ├── HelloAutoConfiguration.java
│ │ │ │ ├── HelloProperties.java
│ │ │ │ └── HelloService.java
│ │ │ └── resources
│ │ │ └── META-INF
│ │ │ └── spring
│ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ │ └── test
│ └── pom.xml
├── hello-spring-boot-starter
│ ├── src
│ │ └── main
│ │ └── resources
│ │ └── META-INF
│ │ └── spring
│ │ └── additional-spring-configuration-metadata.json
│ └── pom.xml
└── pom.xml
4. 实现 autoconfigure 模块
autoconfigure 模块的内容和我们刚才实现的自动配置类完全一样,这里就不再重复了。
5. 实现 starter 模块
starter 模块只需要一个 pom.xml 文件,用于引入 autoconfigure 模块和相关依赖:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-starter-parent</artifactId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hello-spring-boot-starter</artifactId>
<name>Hello Spring Boot Starter</name>
<description>自定义Spring Boot Starter示例</description>
<dependencies>
<!-- 引入autoconfigure模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-autoconfigure</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
6. 配置元数据(可选)
为了让 IDE 能够识别我们的配置属性,提供自动补全和提示功能,我们可以在 starter 模块的src/main/resources/META-INF/spring目录下创建additional-spring-configuration-metadata.json文件:
{
"properties": [
{
"name": "hello.message",
"type": "java.lang.String",
"description": "问候语",
"defaultValue": "Hello, World!"
}
]
}
这样,当用户在application.yml中输入hello.message时,IDE 会自动提示这个属性的含义和默认值。
7. 打包安装
在根目录执行mvn install命令,将两个模块都安装到本地 Maven 仓库。
8. 测试使用
创建一个 Spring Boot 项目,引入我们自定义的 Starter:
XML
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
然后就可以像使用官方 Starter 一样使用我们的自定义 Starter 了!
五、最佳实践与避坑指南
1. 自动配置最佳实践
- 使用 @AutoConfiguration 注解 :Spring Boot 3.x 推荐使用
@AutoConfiguration替代@Configuration来标记自动配置类 - 合理使用条件注解 :使用
@ConditionalOnClass、@ConditionalOnMissingBean等条件注解,让自动配置更加灵活 - 提供合理的默认值:配置属性应该提供合理的默认值,让用户不需要任何配置就能使用
- 支持配置覆盖:允许用户通过配置文件覆盖默认值
- 避免硬编码:所有可配置的参数都应该放到配置属性类中
2. Starter 开发最佳实践
- 遵循命名规范 :第三方 Starter 命名为
xxx-spring-boot-starter - 分离 autoconfigure 和 starter 模块:将自动配置和依赖管理分开,更加灵活
- 最小依赖原则:只引入必要的依赖,避免引入不必要的依赖
- 提供配置元数据 :添加
additional-spring-configuration-metadata.json文件,提供 IDE 提示 - 编写文档:提供详细的使用文档,说明如何配置和使用 Starter
3. 常见坑与解决方案
坑 1:自动配置不生效
常见原因:
- Spring Boot 3.x 中仍然使用旧的
spring.factories配置方式 - 配置文件路径或文件名错误(大小写敏感)
- 条件注解不满足,比如类路径下缺少必要的依赖
- 主配置类的包扫描范围不包含自动配置类
解决方案:
- Spring Boot 3.x 必须使用新的
AutoConfiguration.imports文件 - 检查配置文件的路径和文件名是否完全正确
- 检查条件注解是否满足
- 使用
@SpringBootApplication(scanBasePackages = "com.example")指定包扫描范围
坑 2:自定义 Bean 覆盖了自动配置的 Bean
问题:当我们自定义了一个和自动配置同名的 Bean 时,会覆盖自动配置的 Bean。
解决方案 :如果需要覆盖自动配置的 Bean,明确使用@Bean注解注册自己的 Bean;如果不需要覆盖,避免使用相同的 Bean 名称。
坑 3:条件注解使用错误
常见错误:
@ConditionalOnBean和@ConditionalOnMissingBean的顺序搞反@ConditionalOnProperty的属性名写错- 条件注解的位置放错,比如放在方法上而不是类上
解决方案:仔细阅读条件注解的文档,确保使用正确。
六、高频面试题解答
-
问:Spring Boot 自动装配的底层原理是什么? 答:Spring Boot 自动装配的核心是
@EnableAutoConfiguration注解。它通过 SPI 机制从配置文件中加载所有的自动配置类,然后根据条件注解过滤掉不符合条件的类,最后将符合条件的自动配置类中的 Bean 注册到 Spring 容器中。 -
问:Spring Boot 3.x 为什么废弃了 spring.factories? 答:Spring Boot 3.x 废弃 spring.factories 主要是为了性能优化、模块化支持、类型安全和 GraalVM 原生支持。新的
AutoConfiguration.imports文件机制是静态加载,启动速度更快,与 Java 模块系统兼容性更好。 -
问:spring.factories 和 AutoConfiguration.imports 有什么区别? 答:spring.factories 是键值对形式,支持多个扩展点;AutoConfiguration.imports 是纯类名列表,只用于自动配置。AutoConfiguration.imports 性能更好,类型更安全,是 Spring Boot 3.x 推荐的方式。
-
问:如何自定义一个 Spring Boot Starter? 答:自定义 Spring Boot Starter 的步骤:1. 创建 autoconfigure 模块,编写自动配置类、配置属性类和服务类;2. 创建 starter 模块,引入 autoconfigure 模块和相关依赖;3. 配置自动配置文件;4. 打包安装。
-
问:@ConditionalOnMissingBean 注解的作用是什么? 答:
@ConditionalOnMissingBean注解的作用是当容器中不存在指定的 Bean 时,才注册这个 Bean。它允许用户自定义 Bean 来覆盖自动配置的 Bean,是自动配置中最常用的注解之一。 -
问:自动配置的执行顺序是怎样的? 答:自动配置类的执行顺序可以通过
@AutoConfigureBefore、@AutoConfigureAfter和@AutoConfigureOrder注解来控制。默认情况下,自动配置类的执行顺序是不确定的。
七、总结
Spring Boot 自动装配是 Spring Boot 最成功的特性之一,它通过约定大于配置的思想,大大简化了 Spring 应用的开发和配置。
回顾一下全文的核心内容:
- 自动装配的核心是
@EnableAutoConfiguration注解 - Spring Boot 3.x 废弃了
spring.factories,改用了新的AutoConfiguration.imports文件格式 - 条件注解是自动装配的灵魂,允许我们根据特定条件决定是否注册 Bean
- 自定义自动配置只需要编写自动配置类和配置文件
- 自定义 Starter 需要分离 autoconfigure 和 starter 模块,遵循命名规范
理解了自动装配的原理,你就不再是只会用 Spring Boot 的 "API 调用者",而是真正理解了 Spring Boot 的设计哲学,能够自己开发通用组件,提高团队的开发效率。