Starter 机制
问题
Spring Boot Starter 是什么?如何自定义一个 Starter?
答案
Starter 的本质
Starter 是 Spring Boot 的 依赖描述符——引入一个 starter 就自动引入该场景所需的所有依赖 + 自动配置。
Starter = 依赖聚合 + 自动配置
Starter 本身通常不包含代码,只做两件事:
- 聚合依赖:通过
pom.xml引入该场景需要的 jar 包 - 触发自动配置:依赖中的
spring-boot-autoconfigure模块包含@Conditional配置类
常用官方 Starter
| Starter | 功能 |
|---|---|
spring-boot-starter-web | Web 开发(Tomcat + Spring MVC) |
spring-boot-starter-data-jpa | JPA 持久层(Hibernate) |
spring-boot-starter-data-redis | Redis 缓存 |
spring-boot-starter-security | Spring Security 认证授权 |
spring-boot-starter-test | 测试(JUnit5 + Mockito) |
spring-boot-starter-actuator | 应用监控 |
spring-boot-starter-validation | 参数校验(Hibernate Validator) |
spring-boot-starter-amqp | RabbitMQ 消息队列 |
spring-boot-starter-cache | 缓存抽象 |
命名规范
| 类型 | 命名格式 | 示例 |
|---|---|---|
| 官方 Starter | spring-boot-starter-{name} | spring-boot-starter-web |
| 第三方 Starter | {name}-spring-boot-starter | mybatis-spring-boot-starter |
自定义 Starter
一个完整的自定义 Starter 通常包含 两个模块:
步骤 1:创建自动配置模块
my-spring-boot-autoconfigure/MyProperties.java
@ConfigurationProperties(prefix = "my.sms")
public class SmsProperties {
/** 是否启用 */
private boolean enabled = true;
/** AccessKey */
private String accessKey;
/** SecretKey */
private String secretKey;
/** 签名 */
private String signName;
// getter/setter...
}
my-spring-boot-autoconfigure/SmsService.java
public class SmsService {
private final SmsProperties properties;
public SmsService(SmsProperties properties) {
this.properties = properties;
}
public void send(String phone, String templateCode, Map<String, String> params) {
// 发送短信的实际逻辑
System.out.println("发送短信到 " + phone + ",使用签名:" + properties.getSignName());
}
}
my-spring-boot-autoconfigure/SmsAutoConfiguration.java
@AutoConfiguration
// classpath 中有 SmsService 类才生效
@ConditionalOnClass(SmsService.class)
// 配置 my.sms.enabled=true 时才生效(默认 true)
@ConditionalOnProperty(prefix = "my.sms", name = "enabled", havingValue = "true", matchIfMissing = true)
// 绑定配置属性
@EnableConfigurationProperties(SmsProperties.class)
public class SmsAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 用户未自定义时才注册
public SmsService smsService(SmsProperties properties) {
return new SmsService(properties);
}
}
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.sms.SmsAutoConfiguration
步骤 2:创建 Starter 模块
Starter 模块只有一个 pom.xml,聚合依赖:
sms-spring-boot-starter/pom.xml
<dependencies>
<!-- 引入自动配置模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>sms-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 引入 SMS SDK -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
</dependency>
</dependencies>
步骤 3:使用
application.yml
my:
sms:
access-key: xxx
secret-key: xxx
sign-name: "MyApp"
使用示例
@Service
public class NotificationService {
@Autowired
private SmsService smsService; // 自动注入
public void notifyUser(String phone) {
smsService.send(phone, "SMS_001", Map.of("code", "123456"));
}
}
常见面试问题
Q1: Spring Boot Starter 的原理是什么?
答案:
Starter 是依赖描述符,本身不含代码。它通过 Maven/Gradle 聚合了该场景所需的所有依赖,引入后 Spring Boot 的自动配置机制(@EnableAutoConfiguration)会根据 classpath 中的类和 @Conditional 条件注解自动注册相关 Bean。
Q2: 如何自定义一个 Starter?
答案:
- 创建 autoconfigure 模块:编写
@AutoConfiguration配置类 +@ConfigurationProperties属性类 + 业务类 - 注册配置类到
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - 创建 starter 模块:只有 pom.xml,引入 autoconfigure 模块和所需依赖
- 使用
@ConditionalOnMissingBean保证用户自定义优先
Q3: 为什么 Starter 要分成两个模块?
答案:
- autoconfigure 模块:包含自动配置逻辑,可以被依赖但不强制引入所有第三方依赖(使用
optional标记) - starter 模块:面向用户,聚合所有必要依赖
分离后,如果用户只想用部分功能,可以直接依赖 autoconfigure 模块并自行选择依赖。不过小型项目中合并成一个模块也是可以的。
Q4: spring-boot-starter-parent 的作用?
答案:
spring-boot-starter-parent 是一个父 POM,提供:
- 依赖版本管理:统一管理所有 Spring 生态的依赖版本,避免版本冲突
- 默认配置:编译版本、编码格式、资源过滤
- 插件管理:spring-boot-maven-plugin 等
如果项目已有父 POM,可以用 spring-boot-dependencies 的 BOM 方式替代。
相关链接
- Spring Boot 官方文档 - Starters
- 自动配置原理 - @EnableAutoConfiguration 详解
- Spring 常用注解 - @Conditional 系列注解