starter 机制
SpringBoot 采用约定大于配置思想,starter 是此思想的落地载体
starter 是将功能依赖 + 默认配置 + 自动装配打包成一个 jar,项目只要引入此 jar 即可获得完整能力,无需关心底层到底需要哪些库、怎么配 Bean
starter 规范
-
命名
官方:
spring-boot-starter-*,如spring-boot-starter-web第三方:
xxx-spring-boot-starter,如mybatis-spring-boot-starter -
版本管理
统一继承 spring-boot-dependencies BOM,避免传递版本冲突
-
模块划分
xxx-spring-boot-starter(空壳,只管理依赖) xxx-spring-boot-autoconfigure(自动配置代码) xxx-spring-boot-starter-core(可选,纯业务 API)通过合理拆分模块,实现职责单一、可插拔
-
自动配置类
使用注解 @Configuration,@AutoConfiguration 从 3.x 起替代 @Configuration
-
条件注解
使用 @ConditionalOnClass、@ConditionalOnProperty、@ConditionalOnMissingBean 等,防止重复装配、保证可覆盖
-
配置元数据
提供 spring-configuration-metadata.json,辅助 IDE 对配置自动提示
-
SPI 注册
配置文件:
- META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(3.x 版本)
- spring.factories(2.x 版本)
可同时提供两个版本来提高兼容性
开发实践
以企业中短信功能为场景,封装 SMS starter
SMS starter 分为两个模块
- sms-spring-boot-autoconfigure:自动配置、核心功能
- sms-spring-boot-stater:依赖管理
autoconfigure 模块
配置项类
typescript
@Data
@ConfigurationProperties(prefix = "sms")
public class SmsProperties {
// 开关
private boolean enabled;
private String accessKey;
private String secretKey;
private String region;
}
核心功能接口与实现
typescript
// SMS 功能模板类
public interface SmsTemplate {
SendResult send(String mobile, String sign, String template, Map<String,String> params);
}
// 阿里云 SMS 功能实现
public class AliyunSmsTemplate implements SmsTemplate {
// implement...
}
自动配置类
less
@AutoConfiguration // 3.x 版本代替 @Configuration
@ConditionalOnClass(SmsTemplate.class)
@EnableConfigurationProperties(SmsProperties.class)
@ConditionalOnProperty(prefix = "sms", name = "enabled", matchIfMissing = true)
public class SmsAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SmsTemplate smsTemplate(SmsProperties props) {
return new AliyunSmsTemplate(props);
}
}
注册 SPI
创建文件 src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
配置自动配置类全类名
com.example.sms.boot.SmsAutoConfiguration
配置元数据(可选)
创建文件 src/main/resources/META-INF/additional-spring-configuration-metadata.json
json
{
"properties": [
{
"name": "sms.enabled",
"type": "java.lang.Boolean",
"defaultValue": true,
"description": "是否开启短信服务."
},
{
"name": "sms.access-key",
"type": "java.lang.String",
"description": "云厂商 AccessKey."
}
]
}
可以配合 spring-boot-configuration-processor 或者 spring-boot-properties-maven-plugin 来自动生成此文件
starter 模块
xml
<dependencies>
<!-- 把 autoconfigure 与必要 SDK 全部聚合 -->
<dependency>
<groupId>com.example.sms</groupId>
<artifactId>sms-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 阿里云短信 SDK 示例 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.24</version>
</dependency>
</dependencies>
starter 的使用
引入 starter
xml
<dependency>
<groupId>com.example.sms</groupId>
<artifactId>sms-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
yaml 配置
yaml
sms:
access-key: xxxxx
secret-key: xxxxx
region: cn-hangzhou
注入使用
less
@RestController
class RegisterController {
// 注入 smsTemplate
@Resource
private SmsTemplate smsTemplate;
@PostMapping("/code")
public String sendCode(@RequestParam String mobile) {
// 使用 smsTemplate
// smsTemplate.send(...);
return "ok";
}
}
@Enable 注解
在 starter 开发中一个很重要的步骤是注册 SPI,这是 SpringBoot 能自动扫描到 Configuration 从而进行自动配置的原因
除了 SPI 注册的方式,往往还能看到许多应用提供了 @EnableXXX 注解,用于手动指定是否开启功能特性
以 SMS starter 为例,编写一个 @EnableSMS 注解
less
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(SmsConfigurationSelector.class)
public @interface EnableSms {
/**
* 是否开启 metrics
*/
boolean metrics() default true;
}
原理是利用 @Import 把指定配置类直接送进容器,常见三种模式:
less
@Import(XXX.class) → 普通配置类
@Import(Selector.class) → ImportSelector 可动态返回字符串数组
@Import(Registrar.class) → ImportBeanDefinitionRegistrar 可手动注册 BeanDefinition
实现 SmsConfigurationSelector
typescript
public class SmsConfigurationSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata meta) {
// 拿到注解属性
MultiValueMap<String, Object> attrs =
meta.getAllAnnotationAttributes(EnableSms.class.getName());
boolean metrics = (boolean) attrs.getFirst("metrics");
List<String> list = new ArrayList<>();
list.add("com.example.sms.core.SmsAutoConfiguration");
// 判断是否需要开启 metrics
if (metrics) {
list.add("com.example.sms.actuate.SmsMetricsAutoConfiguration");
}
return list.toArray(new String[0]);
}
}
使用方式
less
@EnableSms(metrics = false)
@SpringBootApplication
public class DemoApplication {
// ...
}
starter 最佳实践:
默认功能使用 SPI 实现自动装配,使用 yaml 实现配置项注入;高级能力配合 @EnableXXX 注解,方便显示开关