外观
自定义
约 2197 字大约 7 分钟
2025-08-24
一、为什么需要自定义 Starter
在 Spring Boot 开发中,我们经常使用官方提供的 Starter(如 spring-boot-starter-web、spring-boot-starter-data-jpa)来简化依赖管理和自动配置。但随着项目发展,我们可能会遇到以下场景:
- 多个项目需要共享相同的功能模块
- 第三方库的集成配置复杂,希望简化使用方式
- 团队内部有统一的技术规范需要自动应用
这时,自定义 Starter 就成为最佳实践,它可以:
- 简化依赖管理:一键引入所有相关依赖
- 实现自动配置:减少重复配置工作
- 提升开发效率:遵循约定优于配置原则
- 统一技术规范:确保团队内技术栈一致性
二、Starter 核心机制
1. 起步依赖(BOM)
起步依赖的本质是将一组相关的依赖打包在一起,简化依赖导入过程。
例如,spring-boot-starter-web 包含了 Web 开发所需的所有基础依赖:
spring-boot-starterspring-boot-starter-jsonspring-boot-starter-tomcatspring-webspring-webmvc
命名规范:
- Spring 官方 Starter:
spring-boot-starter-xxx(如spring-boot-starter-data-jpa) - 第三方 Starter:
xxx-spring-boot-starter(如mybatis-spring-boot-starter)
2. 自动配置原理
Spring Boot 自动配置的核心流程:
- Bean 的发现:通过
META-INF/spring.factories文件 - 条件化加载:基于各种
@Conditional注解 - 参数绑定:使用
@ConfigurationProperties - 自动装配:通过
@EnableAutoConfiguration

关键组件
| 组件 | 作用 | 常用注解 |
|---|---|---|
| 配置类 | 定义自动配置逻辑 | @Configuration |
| 条件注解 | 控制配置加载条件 | @ConditionalOnClass |
| 参数绑定 | 绑定配置文件属性 | @ConfigurationProperties |
| 配置发现 | 注册自动配置类 | META-INF/spring.factories |
三、核心条件注解(必掌握)
自动配置的核心在于条件化加载,以下是最常用的条件注解:
| 注解 | 说明 | 使用场景 |
|---|---|---|
@ConditionalOnClass | 当类路径存在指定类时生效 | 检测依赖是否存在 |
@ConditionalOnMissingBean | 当容器中不存在指定 Bean 时生效 | 避免 Bean 冲突 |
@ConditionalOnProperty | 当配置文件中存在指定属性时生效 | 按配置开关功能 |
@ConditionalOnWebApplication | 当是 Web 应用时生效 | Web 相关配置 |
@ConditionalOnNotWebApplication | 当不是 Web 应用时生效 | 非 Web 相关配置 |
示例:
@Configuration
@ConditionalOnClass(DataSource.class) // 仅当类路径有 DataSource 时加载
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 仅当容器中没有 DataSource 时创建
public DataSource dataSource(DataSourceProperties properties) {
// 创建 DataSource 实例
}
}四、自定义 Starter 实战
1. 项目结构设计
hello-spring-boot
├── hello-spring-boot-starter # Starter 依赖(空,只包含依赖)
├── hello-spring-boot-autoconfigure # 自动配置核心
└── hello-spring-boot-sample # 示例项目(可选)2. 开发步骤详解
步骤 1:创建 autoconfigure 模块
创建项目结构:
# 创建父项目
mvn archetype:generate -DgroupId=com.example -DartifactId=hello-spring-boot -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
# 创建 autoconfigure 模块
cd hello-spring-boot
mvn archetype:generate -DgroupId=com.example -DartifactId=hello-spring-boot-autoconfigure -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false添加必要依赖(pom.xml):
<dependencies>
<!-- Spring Boot 自动配置核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- 配置处理器,生成元数据(IDE 提示) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>步骤 2:定义配置属性类
@ConfigurationProperties(prefix = "hello")
@Data
public class HelloProperties {
/**
* 是否启用 Hello 功能
*/
private boolean enabled = true;
/**
* 欢迎消息
*/
private String message = "Hello, World!";
/**
* 最大欢迎次数
*/
private int maxCount = 10;
}步骤 3:创建自动配置类
@Configuration
@ConditionalOnClass(HelloService.class)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnProperty(prefix = "hello", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnMissingBean
public HelloService helloService(HelloProperties properties) {
return new HelloService(properties.getMessage(), properties.getMaxCount());
}
}步骤 4:注册自动配置类
在 resources/META-INF/spring.factories 中添加:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.hello.autoconfigure.HelloAutoConfiguration重要提示:确保文件编码为 UTF-8,且使用反斜杠
\进行换行
步骤 5:创建 starter 模块
创建 hello-spring-boot-starter 模块:
cd ..
mvn archetype:generate -DgroupId=com.example -DartifactId=hello-spring-boot-starter -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false添加依赖(pom.xml):
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>3. 核心配置说明
配置元数据(可选但推荐)
添加 spring-configuration-metadata.json 到 resources/META-INF/ 目录:
{
"properties": [
{
"name": "hello.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable hello feature.",
"defaultValue": true
},
{
"name": "hello.message",
"type": "java.lang.String",
"description": "The welcome message.",
"defaultValue": "Hello, World!"
},
{
"name": "hello.max-count",
"type": "java.lang.Integer",
"description": "Maximum number of greetings.",
"defaultValue": 10
}
]
}这将使 IDE(如 IntelliJ IDEA)提供配置提示和自动补全。
五、最佳实践
1. 命名规范
- Autoconfigure 模块:
xxx-spring-boot-autoconfigure - Starter 模块:
xxx-spring-boot-starter
示例:
my-redis-spring-boot-autoconfiguremy-redis-spring-boot-starter
2. 版本管理
- 保持版本一致性:autoconfigure 和 starter 模块使用相同版本
- 依赖管理:在父 POM 中管理 Spring Boot 版本
- 避免传递依赖:使用
<optional>true</optional>防止不必要的依赖传递
3. 配置设计原则
提供合理的默认值:确保不配置也能工作
private boolean enabled = true; private String message = "Hello, World!";使用条件化配置:避免与用户自定义 Bean 冲突
@ConditionalOnMissingBean提供明确的配置说明:使用 JavaDoc 注释
/** * 是否启用 Hello 功能 * 默认值: true */ private boolean enabled = true;避免过度配置:只暴露必要的配置项
4. 测试验证
创建一个 sample 项目验证 starter 是否正常工作:
@SpringBootApplication
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
@Bean
public CommandLineRunner demo(HelloService helloService) {
return args -> {
helloService.greet();
};
}
}application.yml:
hello:
message: "Custom Hello!"
max-count: 5六、常见问题与解决方案
1. 配置不生效?
- 检查 spring.factories:确保文件位置和格式正确
- 检查条件注解:确保满足所有条件
- 启用调试:启动时添加
--debug参数java -jar app.jar --debug
2. 如何查看自动配置报告?
在 application.yml 中添加:
debug: true启动应用后,控制台会输出自动配置报告,显示哪些配置已启用/已排除。
3. 如何避免与用户自定义 Bean 冲突?
使用 @ConditionalOnMissingBean 确保只在用户未定义时创建:
@Bean
@ConditionalOnMissingBean
public HelloService helloService() {
return new HelloService();
}4. 如何实现条件化配置?
场景:仅当类路径有 Redis 依赖时才启用 Redis 配置
@Configuration
@ConditionalOnClass(RedisConnectionFactory.class)
public class RedisAutoConfiguration {
// Redis 相关配置
}5. 如何实现配置属性验证?
@ConfigurationProperties(prefix = "hello")
@Validated
public class HelloProperties {
@NotNull
@Size(min = 1, max = 50)
private String message;
@Min(1)
@Max(100)
private int maxCount = 10;
// getters and setters
}需要添加验证依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>七、高级技巧
1. 多环境配置支持
@Configuration
@ConditionalOnProperty(prefix = "hello", name = "enabled", matchIfMissing = true)
public class HelloAutoConfiguration {
@Bean
@Profile("dev")
public HelloService devHelloService() {
return new HelloService("Development: Hello!", 20);
}
@Bean
@Profile("prod")
public HelloService prodHelloService() {
return new HelloService("Production: Hello!", 5);
}
}2. 动态条件判断
创建自定义条件类:
public class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String property = context.getEnvironment().getProperty("custom.property");
return "enabled".equals(property);
}
}使用自定义条件:
@Configuration
@Conditional(CustomCondition.class)
public class CustomAutoConfiguration {
// 配置
}3. 自动配置排序
@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyCustomAutoConfiguration {
// 依赖于 DataSource 的配置
}八、完整示例:Hello Starter
1. 项目结构
hello-spring-boot
├── hello-spring-boot-autoconfigure
│ ├── src/main/java
│ │ └── com/example/hello/autoconfigure
│ │ ├── HelloAutoConfiguration.java
│ │ ├── HelloProperties.java
│ │ └── HelloService.java
│ └── src/main/resources
│ └── META-INF
│ ├── spring.factories
│ └── spring-configuration-metadata.json
└── hello-spring-boot-starter
└── pom.xml2. 核心代码
HelloProperties.java:
@ConfigurationProperties(prefix = "hello")
@Data
public class HelloProperties {
/**
* 是否启用 Hello 功能
*/
private boolean enabled = true;
/**
* 欢迎消息
*/
private String message = "Hello, World!";
/**
* 最大欢迎次数
*/
private int maxCount = 10;
}HelloService.java:
public class HelloService {
private final String message;
private final int maxCount;
public HelloService(String message, int maxCount) {
this.message = message;
this.maxCount = maxCount;
}
public void greet() {
for (int i = 0; i < maxCount; i++) {
System.out.println(message);
}
}
}HelloAutoConfiguration.java:
@Configuration
@ConditionalOnClass(HelloService.class)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
@Bean
@ConditionalOnProperty(prefix = "hello", name = "enabled", matchIfMissing = true)
@ConditionalOnMissingBean
public HelloService helloService(HelloProperties properties) {
return new HelloService(properties.getMessage(), properties.getMaxCount());
}
}spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.hello.autoconfigure.HelloAutoConfiguration3. 使用方式
添加依赖:
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>配置 application.yml:
hello:
message: "Welcome to Spring Boot!"
max-count: 3使用服务:
@RestController
public class HelloController {
private final HelloService helloService;
public HelloController(HelloService helloService) {
this.helloService = helloService;
}
@GetMapping("/hello")
public String hello() {
helloService.greet();
return "Greeting completed!";
}
}九、总结
1. 自定义 Starter 的核心价值
- 简化依赖管理:一键引入所有相关依赖
- 实现自动配置:减少重复配置工作
- 提升开发效率:遵循约定优于配置原则
- 统一技术规范:确保团队内技术栈一致性
2. 开发 Checklist
3. 避坑指南
- 不要包含 starter 依赖:autoconfigure 模块不应包含 starter 依赖
- 避免传递不必要的依赖:使用
<optional>true</optional> - 不要强制覆盖用户配置:使用
@ConditionalOnMissingBean - 不要硬编码配置路径:使用标准配置属性
- 避免循环依赖:注意自动配置类的加载顺序
