自定义 Spring Boot Starter 面试要点
1. 什么是 Spring Boot Starter?
Spring Boot Starter 是一组方便的依赖描述符,你可以在项目中包含这些描述符,
从而获得所需的所有依赖项。它们简化了依赖管理和配置,使得开发者能够快速启动和运行
Spring Boot 应用程序。
2. 为什么需要自定义 Starter?
- 代码复用:将常用的功能封装成可重用的组件
- 简化配置:减少重复配置工作
- 统一管理:集中管理特定功能的实现
- 团队协作:提供标准化的解决方案
3. 自定义 Starter 的核心组件
3.1 配置属性类 (@ConfigurationProperties)
@ConfigurationProperties(prefix = "my.starter")
public class MyProperties {
private String prefix = "Hello";
private String suffix = "!";
private boolean enabled = true;
private int repeat = 1;
// getter/setter...
}
3.2 业务服务类
public class MyService {
private final MyProperties properties;
public MyService(MyProperties properties) {
this.properties = properties;
}
// 实现业务逻辑...
}
3.3 自动配置类
@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(prefix = "my.starter", name = "enabled",
havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean(MyService.class)
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
}
3.4 配置文件 (META-INF/spring.factories)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.std.mystarter.MyAutoConfiguration
4. 关键注解说明
- @ConfigurationProperties:用于绑定配置文件中的属性到 Java 对象
- @ConditionalOnClass:当类路径下存在指定类时才进行配置
- @ConditionalOnProperty:根据配置属性的值决定是否进行配置
- @ConditionalOnMissingBean:当容器中不存在指定类型的 Bean 时才创建
- @EnableConfigurationProperties:启用配置属性绑定功能
5. 实现步骤总结
- 创建业务类:实现核心功能
- 创建配置属性类:定义可配置的参数
- 创建自动配置类:定义 Bean 并使用条件注解控制加载时机
- 注册自动配置:在 spring.factories 文件中注册配置类
- 添加配置元数据:提供 IDE 提示支持
6. 条件注解的使用场景
- @ConditionalOnClass:依赖的类存在时才配置
- @ConditionalOnMissingBean:避免重复创建 Bean
- @ConditionalOnProperty:根据配置开关决定是否启用
- @ConditionalOnResource:资源存在时才配置
- @ConditionalOnWebApplication:Web 环境下才配置
7. 最佳实践
- 命名规范:使用
xxx-spring-boot-starter的命名方式 - 依赖传递:确保 Starter 包含所有必要依赖
- 配置验证:对配置参数进行有效性校验
- 文档完善:提供清晰的使用说明
- 版本管理:合理管理依赖版本
8. 注意事项
- 避免循环依赖
- 合理使用条件注解
- 提供合理的默认值
- 考虑线程安全问题
- 做好异常处理
9. 实际应用场景
- 数据库连接池配置
- 缓存集成
- 消息队列集成
- 监控和健康检查
- 日志框架集成
- 第三方 API 集成
1. 项目概述
本项目演示了如何开发一个自定义的 Spring Boot Starter - service-zstarter,以及如何在另一个模块 my-bootstarter-test 中使用它。
2. 项目结构
spring-cloud-alibaba-demo/
├── service-zstarter/ # 自定义 Starter 模块
│ ├── src/main/java/com/std/mystarter/
│ │ ├── MyAutoConfiguration.java # 自动配置类
│ │ ├── MyProperties.java # 配置属性类
│ │ ├── MyService.java # 业务服务类
│ │ └── MyCondition.java # 条件判断类
│ ├── src/main/resources/META-INF/
│ │ └── additional-spring-configuration-metadata.json # 配置元数据
│ └── pom.xml
└── my-bootstarter-test/ # 测试模块
├── src/main/java/com/std/DemoApplication.java
├── src/main/resources/application.yml
└── pom.xml
3. 开发步骤详解
3.1 创建自定义 Starter (service-zstarter)
3.1.1 定义业务服务类 (MyService.java)
package com.std.mystarter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyService {
private static final Logger logger = LoggerFactory.getLogger(MyService.class);
private final MyProperties properties;
public MyService(MyProperties properties) {
this.properties = properties;
logger.info("MyService initialized with properties: {}", properties);
}
public String sayHello(String name) {
if (!properties.isEnabled()) {
return "Service is disabled";
}
StringBuilder result = new StringBuilder();
for (int i = 0; i < properties.getRepeat(); i++) {
result.append(properties.getPrefix())
.append(" ")
.append(name)
.append(properties.getSuffix());
if (i < properties.getRepeat() - 1) {
result.append(" ");
}
}
return result.toString();
}
public void logConfig() {
logger.info("MyService Configuration:");
logger.info(" Prefix: {}", properties.getPrefix());
logger.info(" Suffix: {}", properties.getSuffix());
logger.info(" Enabled: {}", properties.isEnabled());
logger.info(" Repeat: {}", properties.getRepeat());
}
}
3.1.2 定义配置属性类 (MyProperties.java)
package com.std.mystarter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.starter")
public class MyProperties {
// 默认配置值
private String prefix = "Hello";
private String suffix = "!";
private boolean enabled = true;
private int repeat = 1;
// Getter 和 Setter 方法
public String getPrefix() { return prefix; }
public void setPrefix(String prefix) { this.prefix = prefix; }
public String getSuffix() { return suffix; }
public void setSuffix(String suffix) { this.suffix = suffix; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public int getRepeat() { return repeat; }
public void setRepeat(int repeat) { this.repeat = repeat; }
}
3.1.3 创建自动配置类 (MyAutoConfiguration.java)
package com.std.mystarter;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@Configuration // Spring Boot 2.x 使用 @Configuration
@ConditionalOnClass(MyService.class) // 类路径存在 MyService 时才生效
@ConditionalOnProperty(prefix = "my.starter", name = "enabled",
havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyProperties.class) // 使配置属性生效
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean(MyService.class)
public MyService myService(MyProperties properties) {
return new MyService(properties);
}
@Bean
@ConditionalOnMissingBean(name = "myServiceHelper")
public MyServiceHelper myServiceHelper(MyService myService) {
return new MyServiceHelper(myService);
}
}
3.1.4 添加配置元数据文件 (additional-spring-configuration-metadata.json)
{
"properties": [
{
"name": "my.starter.prefix",
"type": "java.lang.String",
"description": "消息前缀",
"defaultValue": "Hello"
},
{
"name": "my.starter.suffix",
"type": "java.lang.String",
"description": "消息后缀",
"defaultValue": "!"
},
{
"name": "my.starter.enabled",
"type": "java.lang.Boolean",
"description": "是否启用服务",
"defaultValue": true
},
{
"name": "my.starter.repeat",
"type": "java.lang.Integer",
"description": "消息重复次数",
"defaultValue": 1
}
]
}
3.1.5 配置自动装配 (spring.factories)
在 src/main/resources/META-INF/spring.factories 文件中添加:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.std.mystarter.MyAutoConfiguration
3.1.6 配置 POM 文件 (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>
<parent>
<groupId>com.std</groupId>
<artifactId>spring-cloud-alibaba-demo</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>service-zstarter</artifactId>
<packaging>jar</packaging>
<name>service-zstarter</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Boot 自动配置核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 配置属性处理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 条件注解支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 可选:如果需要日志 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
3.2 测试自定义 Starter (my-bootstarter-test)
3.2.1 创建测试应用 (DemoApplication.java)
package com.std;
import com.std.mystarter.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Autowired
private MyService myService;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) {
System.out.println("测试自定义 Starter:");
System.out.println(myService.sayHello("Spring Boot"));
myService.logConfig();
}
}
3.2.2 配置自定义参数 (application.yml)
my:
starter:
prefix: "Hi"
suffix: "!!!"
enabled: true
repeat: 3
# 启用调试模式查看自动配置报告
debug: true
3.2.3 配置测试模块依赖 (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>
<parent>
<groupId>com.std</groupId>
<artifactId>spring-cloud-alibaba-demo</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>my-bootstarter-test</artifactId>
<packaging>jar</packaging>
<name>my-bootstarter-test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.std</groupId>
<artifactId>service-zstarter</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
4. 关键概念说明
4.1 自动配置原理
- 使用 [@ConditionalOnClass](file:///E:/javaWork/std/spring-cloud-alibaba-demo/service-user/src/main/java/com/std/config/RedisConfig.java#L8-L8) 注解确保类路径中有必要的类时才进行配置
- 使用 [@ConditionalOnProperty](file:///E:/javaWork/std/spring-cloud-alibaba-demo/service-user/src/main/java/com/std/config/RedisConfig.java#L9-L9) 注解根据配置属性决定是否启用配置
- 使用 [@ConditionalOnMissingBean](file:///E:/javaWork/std/spring-cloud-alibaba-demo/service-user/src/main/java/com/std/config/RedisConfig.java#L10-L10) 注解确保只有在没有相同类型的 Bean 时才创建新 Bean
4.2 配置属性绑定
- 使用 [@ConfigurationProperties](file:///E:/javaWork/std/spring-cloud-alibaba-demo/common/src/main/java/com/std/config/RedisConfig.java#L10-L10) 注解将配置文件中的属性绑定到 Java 对象
- 配置前缀使用
my.starter,对应的配置项如my.starter.prefix
4.3 条件化配置
- Spring Boot 提供了多种条件注解,可以根据不同条件激活配置
- 常用的条件注解包括 [@ConditionalOnClass](file:///E:/javaWork/std/spring-cloud-alibaba-demo/service-user/src/main/java/com/std/config/RedisConfig.java#L8-L8)、[@ConditionalOnMissingBean](file:///E:/javaWork/std/spring-cloud-alibaba-demo/service-user/src/main/java/com/std/config/RedisConfig.java#L10-L10)、[@ConditionalOnProperty](file:///E:/javaWork/std/spring-cloud-alibaba-demo/service-user/src/main/java/com/std/config/RedisConfig.java#L9-L9) 等
5. 构建和使用
要构建和使用此自定义 Starter,请执行以下步骤:
- 构建整个项目:
mvn clean install - 运行测试应用:
cd my-bootstarter-test && mvn spring-boot:run - 应用将输出自定义配置的结果
6. 最佳实践
- 命名规范:Starter 名称通常以
-spring-boot-starter结尾 - 依赖管理:确保 Starter 包含所有必需的依赖项
- 配置元数据:提供配置元数据以支持 IDE 提示
- 条件配置:合理使用条件注解避免冲突
- 文档说明:提供清晰的使用说明和示例

114

被折叠的 条评论
为什么被折叠?



