一句话总结
自定义 Starter 三步走:1)写自动配置类(@AutoConfiguration + @ConditionalOnClass + @Bean + @EnableConfigurationProperties);2)注册自动配置(META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中写入配置类全限定名);3)写属性类(@ConfigurationProperties 绑定 application.yml 配置)。命名规范:官方 starter 叫 spring-boot-starter-xxx,第三方叫 xxx-spring-boot-starter。
初级理解
Starter 项目结构
# 自定义 Starter 项目结构
my-spring-boot-starter/
├── pom.xml
└── src/main/
├── java/com/example/
│ ├── MyService.java # 核心服务类
│ ├── MyProperties.java # 配置属性类
│ └── MyAutoConfiguration.java # 自动配置类
└── resources/
└── META-INF/
└── spring/
└── org.springframework.boot.autoconfigure
.AutoConfiguration.imports # 注册文件
# 命名规范
# 官方:spring-boot-starter-web
# 第三方:mybatis-spring-boot-starter
# 自定义:my-spring-boot-starter
最小实现
# 1. 核心服务类
public class MyService {
private String url;
private int timeout;
public MyService(String url, int timeout) {
this.url = url;
this.timeout = timeout;
}
public String call() {
return "Calling " + url + " with timeout " + timeout;
}
}
# 2. 配置属性类
@ConfigurationProperties(prefix = "my")
public class MyProperties {
private String url = "http://localhost:8080";
private int timeout = 3000;
// getter/setter
}
# 3. 自动配置类
@AutoConfiguration
@EnableConfigurationProperties(MyProperties.class)
@ConditionalOnClass(MyService.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties.getUrl(), properties.getTimeout());
}
}
中级深入
注册自动配置
# Spring Boot 2.7+ 注册方式
# 文件路径:META-INF/spring/
# org.springframework.boot.autoconfigure.AutoConfiguration.imports
# 文件内容(每行一个配置类全限定名):
com.example.MyAutoConfiguration
# Spring Boot 2.7 之前注册方式
# 文件路径:META-INF/spring.factories
# 文件内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration
# 区别
# 2.7+ 使用专用文件,更简洁
# 2.7 之前使用 spring.factories,所有 SPI 混在一起
条件注解实战
# 多种条件组合
@AutoConfiguration
@ConditionalOnClass({MyService.class, RestTemplate.class})
@ConditionalOnProperty(prefix = "my", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties.getUrl(), properties.getTimeout());
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(RestTemplate.class)
public MyHttpClient myHttpClient(RestTemplate restTemplate) {
return new MyHttpClient(restTemplate);
}
}
# 条件说明
# @ConditionalOnClass:classpath 有 MyService 和 RestTemplate
# @ConditionalOnProperty:my.enabled=true(默认 true)
# @ConditionalOnMissingBean:用户没自定义才创建
# @ConditionalOnBean:容器中有 RestTemplate 才创建 MyHttpClient
高级拓展
@ConfigurationProperties 进阶
# 支持嵌套属性
@ConfigurationProperties(prefix = "my")
public class MyProperties {
private String url;
private int timeout;
private Pool pool = new Pool(); // 嵌套对象
public static class Pool {
private int maxSize = 10;
private int minIdle = 2;
// getter/setter
}
}
# application.yml 配置
my:
url: https://api.example.com
timeout: 5000
pool:
max-size: 20
min-idle: 5
# 支持 JSR303 校验
@ConfigurationProperties(prefix = "my")
@Validated
public class MyProperties {
@NotBlank
private String url;
@Min(1000)
@Max(30000)
private int timeout = 3000;
}
Starter 依赖管理
# pom.xml 关键配置
<dependencies>
<!-- 自动配置依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 配置处理器(生成元数据,IDE 提示) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
# 可选依赖(不强制传递)
<dependency>
<groupId>com.example</groupId>
<artifactId>some-lib</artifactId>
<optional>true</optional> <!-- 用户需要时自己引入 -->
</dependency>
实战场景
场景:短信服务 Starter
# 使用方只需引入依赖 + 配置
# pom.xml
<dependency>
<groupId>com.example</groupId>
<artifactId>sms-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
# application.yml
sms:
provider: aliyun # 阿里云 / 腾讯云
access-key: xxx
secret-key: xxx
sign-name: 我的应用
template-id: SMS_123456
# 使用
@Autowired
private SmsService smsService;
public void sendVerifyCode(String phone) {
smsService.send(phone, "您的验证码是:123456");
}
面试模拟
面试官:如何自定义一个 Spring Boot Starter?
你:三步:1)写自动配置类(@AutoConfiguration + @ConditionalOnClass + @Bean);2)在 META-INF/spring/...AutoConfiguration.imports 中注册配置类;3)写属性类(@ConfigurationProperties)。引入 Starter 后自动配置生效,用户只需在 application.yml 中配置参数。
面试官:Starter 命名规范是什么?
你:官方 starter 叫 spring-boot-starter-xxx(如 spring-boot-starter-web),第三方叫 xxx-spring-boot-starter(如 mybatis-spring-boot-starter)。这样能一眼区分官方和第三方。