Spring Boot 自定义 Starter 完整实战手册
一、核心概念与项目结构
1. 什么是 Starter?
- 本质:预配置模块 = 依赖集合 + 自动配置类 + 默认实现
- 核心价值:
- 统一技术栈:团队快速复用标准组件
- 简化配置:隐藏复杂实现细节(如连接池参数)
- 按需加载:通过
@Conditional
实现特性开关
2. 项目目录结构(以短信服务 Starter 为例)
my-sms-starter/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── config/
│ │ │ │ ├── SmsAutoConfiguration.java # 自动配置类
│ │ │ │ └── SmsProperties.java # 配置属性类
│ │ │ └── service/
│ │ │ ├── SmsService.java # 核心服务接口
│ │ │ └── impl/ # 多厂商实现
│ │ │ ├── AliyunSmsImpl.java
│ │ │ └── TencentSmsImpl.java
│ │ └── resources/
│ │ ├── META-INF/
│ │ │ ├── spring/
│ │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports # Spring Boot 3.x+
│ │ │ └── spring.factories # Spring Boot 2.x
│ │ └── application.yml # 默认配置(可选)
│ └── test/ # 单元测试
└── pom.xml # Maven 依赖管理
二、详细实现步骤(以短信服务为例)
1. 创建 Maven 项目(pom.xml)
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-sms-starter</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version> <!-- 确保与 Spring Boot 版本兼容 -->
<relativePath/> <!-- 直接继承 Spring Boot 依赖管理 -->
</parent>
<dependencies>
<!-- Spring Boot 自动配置支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 依赖管理,避免传递冲突 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>provided</scope>
</dependency>
<!-- 处理 @ConfigurationProperties 自动绑定 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Lombok,简化 Java 代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- JUnit 5(仅测试环境使用) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot 编译插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
注意:若需支持 Spring Boot 3.x,需 JDK 17+ 并检查依赖兼容性。
2. 编写配置属性类(绑定 YAML 参数)
// SmsProperties.java
@Data
@ConfigurationProperties(prefix = "sms") // 配置前缀 sms.xxx
public class SmsProperties {
/**
* 短信平台类型(aliyun/tencent/huawei)
*/
private String type = "aliyun";
private String apiKey; // 对应 sms.api-key
private String endpoint = "https://api.sms.com"; // 默认值
private int retry = 3; // 默认重试次数
}
作用:将 application.yml
中的参数映射到 Java 对象。
3. 编写自动配置类(核心)
// SmsAutoConfiguration.java
@Configuration
@EnableConfigurationProperties(SmsProperties.class) // 启用属性绑定
@ConditionalOnClass(SmsService.class) // 检测类路径是否存在 SmsService
@AutoConfigureAfter(CacheAutoConfiguration.class) // 明确装配顺序
public class SmsAutoConfiguration {
// 阿里云短信服务 Bean
@Bean
@ConditionalOnMissingBean // 用户未自定义时创建默认 Bean
@ConditionalOnProperty(prefix = "sms", name = "type", havingValue = "aliyun")
public SmsService aliyunSmsService(SmsProperties properties) {
return new AliyunSmsImpl(properties.getApiKey(), properties.getEndpoint(), properties.getRetry());
}
// 腾讯云短信服务 Bean
@Bean
@ConditionalOnMissingBean // 用户未自定义时创建默认 Bean
@ConditionalOnProperty(prefix = "sms", name = "type", havingValue = "tencent")
public SmsService tencentSmsService(SmsProperties properties) {
return new TencentSmsImpl(properties.getApiKey(), properties.getEndpoint(), properties.getRetry());
}
}
条件注解解析:
@ConditionalOnClass
:检测是否存在特定类(如 RedisTemplate)@ConditionalOnWebApplication
:仅在 Web 环境生效
4. 服务接口与实现(策略模式)
// SmsService.java
public interface SmsService {
boolean send(String mobile, String content);
}
// AliyunSmsImpl.java
public class AliyunSmsImpl implements SmsService {
private final String apiKey;
private final String endpoint;
private final int retry;
// 使用带参数的构造函数进行初始化
public AliyunSmsImpl(String apiKey, String endpoint, int retry) {
this.apiKey = apiKey;
this.endpoint = endpoint;
this.retry = retry;
}
@Override
public boolean send(String mobile, String content) {
// 阿里云 SDK 具体实现
System.out.println("调用阿里云短信接口,apiKey:" + apiKey + ", endpoint:" + ", retry:" + retry + ", mobile:" + mobile + ", content:" + content);
return true;
}
}
// TencentSmsImpl.java
public class TencentSmsImpl implements SmsService {
private final String apiKey;
private final String endpoint;
private final int retry;
// 使用带参数的构造函数进行初始化
public TencentSmsImpl(String apiKey, String endpoint, int retry) {
this.apiKey = apiKey;
this.endpoint = endpoint;
this.retry = retry;
}
@Override
public boolean send(String mobile, String content) {
// 腾讯云 SDK 具体实现
System.out.println("调用腾讯云短信接口,apiKey:" + apiKey + ", endpoint:" + ", retry:" + retry + ", mobile:" + mobile + ", content:" + content);
return true;
}
}
5. 注册自动配置类(版本差异)
-
Spring Boot 2.x:
在src/main/resources/META-INF/spring.factories
添加:org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.config.SmsAutoConfiguration
-
Spring Boot 3.x:
在src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
添加:com.example.config.SmsAutoConfiguration
重要提示:Spring Boot 2.7+ 已弃用
spring.factories
,必须使用新路径。
6. 打包发布
# 安装到本地仓库
mvn clean install -DskipTests
# 发布到 Nexus 私服
mvn deploy -DaltDeploymentRepository=nexus::default::http://nexus.example.com/repository/maven-releases/
三、使用示例
1. 引入依赖
<dependency>
<groupId>com.example</groupId>
<artifactId>my-sms-starter</artifactId>
<version>1.0.0</version>
</dependency>
2. 配置参数
sms:
type: "tencent"
api-key: "d0d0b33f-87e2-4aac"
endpoint: "https://sms.cloud.prod"
retry: 2
3. 业务代码
@Service
public class TestSmsService {
private final SmsService smsService;
public TestSmsService(SmsService smsService) {
this.smsService = smsService;
}
public void sendSms( ) {
smsService.send("13800138000","短信内容6666");
}
}
四、常见问题排查
问题现象 | 解决方案 |
---|---|
配置不生效 | 检查 @ConfigurationProperties 的 prefix 是否匹配 YAML |
Bean 未创建 | 确认类路径存在 @ConditionalOnClass 指定的类 |
Spring Boot 3.x 不兼容 | 使用 AutoConfiguration.imports 替代 spring.factories |
依赖冲突 | 在 starter 模块中声明 <optional>true</optional> |
五、实际案例参考
-
短信服务 Starter
- 功能:支持阿里云、腾讯云、华为云动态切换,内置签名验证和模板管理。
- 源码:参考开源项目
sms-spring-boot-starter
(Gitee)。
-
分布式锁 Starter
- 功能:封装 Redis/Redisson/ZooKeeper 实现,支持注解式锁(
@DistributedLock
)。 - 设计:通过
@ConditionalOnClass
按需加载不同实现。
- 功能:封装 Redis/Redisson/ZooKeeper 实现,支持注解式锁(