视频看了几百小时还迷糊?关注我,几分钟让你秒懂!
Spring Boot 之所以能“开箱即用”,核心就在于自动装配(Auto-Configuration)。但很多开发者只会说“加了 starter 就自动配置了”,却说不清:
- 为什么引入
spring-boot-starter-data-redis就能直接用RedisTemplate? - 自动配置类什么时候生效?怎么被加载的?
- 如何自定义 Starter?
今天我们就从源码层面,一步步拆解 Spring Boot 自动装配的完整流程,并手把手教你写一个企业级 Starter!
一、需求场景:公司要统一日志格式,需封装一个 LogStarter
你希望其他团队只需:
<dependency> <groupId>com.company</groupId> <artifactId>company-spring-boot-starter-log</artifactId> </dependency>就能自动注入CustomLoggerBean,并支持配置前缀company.log.level。
但你不知道如何让 Spring Boot自动发现并加载你的配置类。
二、反例认知:你以为的“自动”其实是精心设计!
❌ 常见误解:
- “只要类上有 @Configuration 就会自动加载” → 错!必须被 Spring 扫描到。
- “starter 里放个配置类就行” → 错!需通过
spring.factories注册。 - “@Conditional 注解可有可无” → 错!它是自动装配的“开关”。
三、自动装配核心流程(四步走)
步骤1️⃣:启动类上的@SpringBootApplication
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }→ 它是一个组合注解,关键在:
@EnableAutoConfiguration // 核心! @ComponentScan @Configuration步骤2️⃣:@EnableAutoConfiguration导入AutoConfigurationImportSelector
这个 Selector 会在 Spring 容器刷新时执行,做两件事:
- 扫描所有 jar 包下的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
(旧版是META-INF/spring.factories,Spring Boot 2.7+ 已迁移) - 加载其中列出的自动配置类
🔍 示例:
spring-boot-starter-data-redis的org.springframework.boot.autoconfigure.AutoConfiguration.imports内容:
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration步骤3️⃣:条件化加载(@Conditional 系列注解)
即使配置类被加载,也不一定生效!Spring Boot 用条件注解控制:
| 注解 | 作用 |
|---|---|
@ConditionalOnClass | 类路径存在某 class 时生效 |
@ConditionalOnMissingBean | 容器中没有该 Bean 时才创建 |
@ConditionalOnProperty | 配置文件中存在某属性时生效 |
@ConditionalOnWebApplication | 仅 Web 应用生效 |
✅ 以RedisAutoConfiguration为例:
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(RedisOperations.class) // 必须有 Redis 相关类 @ConditionalOnMissingBean(name = "redisTemplate") // 用户没自定义 redisTemplate 才生效 @EnableConfigurationProperties(RedisProperties.class) public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean // 再次检查 public RedisTemplate<Object, Object> redisTemplate(...) { ... } }💡 这就是为什么:你自定义了 RedisTemplate,官方的就不会创建!
步骤4️⃣:属性绑定(@ConfigurationProperties)
自动配置类通常配合@ConfigurationProperties使用:
@ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { private int port = 6379; private String host = "localhost"; // getter/setter }→ 自动将application.yml中的spring.redis.host绑定到该对象。
四、手把手:编写企业级 Starter
目标:提供CustomLogger,支持配置日志级别
第一步:创建company-spring-boot-starter-log模块
src/main/java └── com.company.starter.log ├── CustomLogger.java ├── LogProperties.java └── LogAutoConfiguration.java src/main/resources └── META-INF └── spring └── org.springframework.boot.autoconfigure.AutoConfiguration.imports第二步:编写核心类
// 1. 属性类 @ConfigurationProperties(prefix = "company.log") public class LogProperties { private String level = "INFO"; // getter/setter } // 2. 业务 Bean public class CustomLogger { private final String level; public CustomLogger(String level) { this.level = level; } public void log(String msg) { System.out.println("[" + level + "] " + msg); } } // 3. 自动配置类 @Configuration(proxyBeanMethods = false) @ConditionalOnClass(CustomLogger.class) @EnableConfigurationProperties(LogProperties.class) public class LogAutoConfiguration { @Bean @ConditionalOnMissingBean public CustomLogger customLogger(LogProperties properties) { return new CustomLogger(properties.getLevel()); } }第三步:注册自动配置类
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
com.company.starter.log.LogAutoConfiguration⚠️ 注意:Spring Boot 2.7+ 必须用
.imports文件,不再支持spring.factories!
第四步:使用 Starter
<!-- 引入 --> <dependency> <groupId>com.company</groupId> <artifactId>company-spring-boot-starter-log</artifactId> <version>1.0.0</version> </dependency># application.yml company: log: level: DEBUG@RestController public class TestController { @Autowired private CustomLogger logger; @GetMapping("/test") public String test() { logger.log("Hello from starter!"); return "ok"; } }✅ 启动成功,输出:[DEBUG] Hello from starter!
五、常见问题与陷阱
问题1️⃣:自动配置类没生效?
- 检查
.imports文件路径是否正确; - 检查是否被
@Conditional条件拦截(如缺少依赖类); - 用
--debug启动,查看自动配置报告:
→ 日志中会打印Positive matches / Negative matches。java -jar app.jar --debug
问题2️⃣:属性没绑定?
- 确保
@ConfigurationProperties类有public setter; - 或添加
@ConstructorBinding+@ConfigurationProperties(不可变对象)。
问题3️⃣:和其他 Starter 冲突?
- 使用
@AutoConfigureBefore/@AutoConfigureAfter控制加载顺序:@AutoConfigureAfter(DataSourceAutoConfiguration.class) public class MyAutoConfiguration { ... }
六、面试加分回答
问:Spring Boot 自动装配的底层原理是什么?
✅ 回答:
核心是
@EnableAutoConfiguration+AutoConfigurationImportSelector。
启动时,Spring Boot 会扫描所有依赖 jar 包中的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,
加载其中声明的配置类。
这些配置类通过@Conditional系列注解实现条件化加载,
并结合@ConfigurationProperties绑定外部配置,
最终实现“约定优于配置”的自动装配。
问:为什么自动配置类要放在 starter 里,而不是主应用?
✅ 回答:
Starter 是能力封装单元。
把自动配置逻辑放在 starter 中,可以让多个项目复用,
同时通过条件注解保证只有引入依赖时才激活,
避免主应用臃肿,符合微内核 + 插件化设计思想。
七、最佳实践建议
- ✅ 自动配置类命名规范:
XxxAutoConfiguration - ✅ 属性类命名:
XxxProperties - ✅ 必须使用
@ConditionalOnMissingBean避免覆盖用户自定义 - ✅ 提供
spring-configuration-metadata.json支持 IDE 提示 - ✅ Starter 不要包含业务代码,只做集成和配置
视频看了几百小时还迷糊?关注我,几分钟让你秒懂!