深入理解Spring Boot Starter及如何自定义Starter
Spring Boot Starter本质上是一种依赖管理和自动配置机制。通过引入一个Starter依赖,可以自动引入并配置一系列相关组件,极大地简化开发流程。比如使用spring-boot-starter-web
,可以自动引入Spring MVC、Tomcat服务器、JSON解析器等,无需手动逐个配置。
Starter的自动配置原理
Spring Boot 会扫描所有 classpath
下 JAR 包中的 META-INF/spring.factories
文件,并按照其中的配置进行自动加载。
📌 详细解析
扫描机制
- Spring Boot 使用
SpringFactoriesLoader
类来加载spring.factories
文件中的配置。 - 它会扫描 所有 依赖(包括
libs/
和dependencies
目录中的 JAR 包),寻找META-INF/spring.factories
,然后合并所有的配置项。
- Spring Boot 使用
合并机制
- 如果多个 JAR 包(如
spring-boot-starter-web
、spring-boot-starter-data-jpa
等)都定义了spring.factories
,Spring Boot 会把 所有 JAR 包中的配置合并,然后执行加载。 - 示例:
spring-boot-autoconfigure.jar
的META-INF/spring.factories
可能包含:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
- 另一个 JAR 包
my-custom-starter.jar
可能包含:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.custom.MyCustomAutoConfiguration
- Spring Boot 会把这两部分合并,最终加载:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ com.example.custom.MyCustomAutoConfiguration
- 如果多个 JAR 包(如
加载顺序
- Spring Boot 不保证
spring.factories
配置的执行顺序,如果多个 JAR 包中存在相同的 Key(比如EnableAutoConfiguration
),它们都会被加载,但执行顺序不可预测。 - 如果需要控制加载顺序,可以使用
@AutoConfigureBefore
和@AutoConfigureAfter
。
- Spring Boot 不保证
META-INF/spring.factories
文件的作用
META-INF/spring.factories
是 Spring Boot 的自动配置机制 之一,它的主要作用是:
- 启用 Spring Boot 的自动配置(AutoConfiguration)
- 自动注册 Spring 组件(如监听器、工厂类等)
- 扩展 Spring Boot 功能
📌 spring.factories
作用范围
类型 | 作用 |
---|---|
EnableAutoConfiguration |
自动配置 Spring Boot 组件(最常见) |
ApplicationContextInitializer |
Spring 上下文初始化时执行 |
ApplicationListener |
监听 Spring 事件 |
FailureAnalyzer |
处理异常分析,提供更友好的错误信息 |
EnvironmentPostProcessor |
修改 Spring Environment ,在启动时修改配置 |
📌 SpringFactoriesLoader
如何扫描?
Spring Boot 使用 SpringFactoriesLoader.loadFactoryNames(Class<?> factoryType, ClassLoader classLoader)
方法来扫描所有 META-INF/spring.factories
:
public static List<String> loadFactoryNames(Class<?> factoryType, ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
loadSpringFactories(classLoader)
方法会 遍历所有 JAR 包,加载spring.factories
。- 所有 JAR 包的
spring.factories
文件的内容都会被合并并解析。
📌 如何避免 spring.factories
冲突?
如果多个 JAR 包的 spring.factories
中包含 相同的 Key,但不同的实现(比如多个 JAR 里都有 EnableAutoConfiguration
),可能会导致:
- 重复加载(多个类都被注册)
- 冲突(不同的类覆盖了同一个 Bean)
解决方案
使用
spring-boot-autoconfigure
提供的新方式- Spring Boot 2.7+ 推荐使用
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
- 这样可以更好地控制哪些配置应该被加载,不会导致
spring.factories
的全局合并问题。
- Spring Boot 2.7+ 推荐使用
使用
@ConditionalOnMissingBean
避免重复加载- 在自动配置类中使用
@ConditionalOnMissingBean
,避免同一个 Bean 被多次注册:
@Configuration @ConditionalOnClass(MyService.class) public class MyAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService() { return new MyService(); } }
- 在自动配置类中使用
使用
@AutoConfigureBefore
或@AutoConfigureAfter
- 控制自动配置类的加载顺序:
@Configuration @AutoConfigureBefore(DataSourceAutoConfiguration.class) public class MyCustomAutoConfiguration { // 自定义配置 }
📌 结论
✅ Spring Boot 确实会扫描所有 JAR 包的 META-INF/spring.factories
文件,并合并所有配置项。
✅ 这使得 Starter 组件可以自动注册需要的 Bean 和配置,但也可能导致 Bean 冲突或重复加载的问题。
✅ Spring Boot 2.7+ 推荐使用 AutoConfiguration.imports
作为更可控的替代方案。
如何自定义一个Starter(以钉钉异常通知为例)
假设你想要实现当接口异常发生时自动发送钉钉通知的功能,创建一个Starter将是一个理想选择。
1. 创建新项目模块
例如:mycompany-starter-dingtalk
四、Starter实现步骤
- 创建自动配置类:
@Configuration
@ConditionalOnClass(DingTalkNotifier.class)
@EnableConfigurationProperties(DingTalkProperties.class)
public class DingTalkAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DingTalkNotifier dingTalkNotifier(DingTalkProperties properties) {
return new DingTalkNotifier(properties.getWebhookUrl());
}
@Bean
public GlobalExceptionHandler globalExceptionHandler(DingTalkNotifier dingTalkNotifier) {
return new GlobalExceptionHandler(dingTalkNotifier);
}
}
- 定义属性类绑定用户配置
@ConfigurationProperties(prefix = "dingding")
public class DingTalkProperties {
private String webhookUrl;
public String getWebhookUrl() { return webhookUrl; }
public void setWebhookUrl(String webhookUrl) { this.webhookUrl = webhookUrl; }
}
在用户的application.yml
中配置:
dingding:
webhook-url: "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
注册自动配置
在项目的resources目录下创建META-INF/spring.factories
:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.dingtalk.autoconfigure.DingTalkAutoConfiguration
Spring Boot启动时会自动扫描并加载这个配置。
五、Starter的命名规范建议
官方并没有强制性的命名约束,但 Spring Boot 社区和官方 Starter 一般遵循一些最佳实践,推荐使用 统一的命名规范,以提高可读性和易用性。
1️⃣ 官方 Starter 的命名规范
Spring Boot 官方 Starter 的命名规则通常是:
spring-boot-starter-<技术名称>
📌 典型官方 Starter 例子
Starter | 说明 |
---|---|
spring-boot-starter-web |
Web 开发 Starter,包含 Spring MVC、Tomcat 等 |
spring-boot-starter-data-jpa |
JPA 数据访问 Starter |
spring-boot-starter-security |
Spring Security Starter |
spring-boot-starter-thymeleaf |
Thymeleaf 模板引擎 Starter |
👉 结论:
- 所有官方 Starter 以
spring-boot-starter-
开头,然后跟 具体的技术名称。 - 这让开发者一眼就能知道 它是官方的,并且它支持什么技术。
2️⃣ 自定义 Starter 的推荐命名规则
对于 自定义 Starter,社区推荐使用:
<公司/团队前缀>-starter-<功能名称>
或者:
<组织名称>-spring-boot-starter-<功能名称>
📌 推荐命名方式
命名示例 | 适用场景 |
---|---|
mycompany-starter-dingtalk |
企业内部使用,用于钉钉异常通知 |
com-example-spring-boot-starter-logging |
社区 Starter,支持 Spring Boot 日志增强 |
custom-starter-redis |
通用 Starter,适用于 Redis 相关增强功能 |
awesome-spring-boot-starter-cache |
开源项目,提供缓存增强 |
📌 推荐命名规则
✅ 避免以 spring-boot-starter-
开头
- 这样可以 避免和官方 Starter 混淆,让用户明确知道它是第三方 Starter。
- 推荐:
mycompany-starter-xxx
或xxx-spring-boot-starter
- 不推荐:
spring-boot-starter-xxx
❌(可能导致误以为是官方的)
✅ 前缀代表团队或组织名称
- 例如:
alibaba-starter-seata
(阿里巴巴 Seata 事务管理)baidu-starter-paddlepaddle
(百度 PaddlePaddle AI 框架)mycompany-starter-wechat
(企业内部的微信消息推送)
✅ 后缀描述功能
starter-dingtalk
(钉钉通知)starter-mq
(消息队列支持)starter-log-enhancer
(日志增强)
3️⃣ 约束和注意事项
🚀 官方约束
Spring Boot 不会 强制要求 Starter 必须符合某种命名规则,但官方有一些约定:
- 官方 Starter 需要由 Spring 团队维护(放在
org.springframework.boot
下面)。 - 社区或第三方 Starter 不能以
spring-boot-starter-
开头,避免误导用户。
🚀 依赖命名
如果 Starter 需要提供 自动配置,通常需要提供:
- 核心依赖(starter 依赖):
<artifactId>mycompany-starter-dingtalk</artifactId>
- 自动配置依赖(autoconfigure 依赖):
<artifactId>mycompany-starter-dingtalk-autoconfigure</artifactId>
这样可以 拆分 Starter 的自动配置和核心功能,提高灵活性。
📌 结论
✅ 官方 Starter 以 spring-boot-starter-
开头,后面跟具体技术,如 spring-boot-starter-web
。
✅ 自定义 Starter 推荐 mycompany-starter-xxx
或 xxx-spring-boot-starter
,避免与官方混淆。
✅ 组织前缀 可加 mycompany-
或 com-example-
,以区分不同的公司或团队。
✅ 最好拆分 starter
和 starter-autoconfigure
,增强模块化和可扩展性。