SpringBoot Starter自定义开发

SpringBoot Starter自定义开发

Spring Boot 简化了配置,但日志管理依然需要重视。日志配置、链路追踪、排查思路都是日常开发中会遇到的问题。本文讲实际项目中的日志管理经验。

Starter 命名规范

类型 命名格式 示例
官方 Starter spring-boot-starter-* spring-boot-starter-web
第三方 Starter *-spring-boot-starter mybatis-spring-boot-starter

开发步骤

#

1. 创建 Maven 项目

<!-- pom.xml -->
<project>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.x</version>
</parent>

<artifactId>my-service-spring-boot-starter</artifactId>
<version>1.0.0</version>

<dependencies>
<!-- 自动配置 -->
<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>
</dependencies>
</project>

#

2. 创建配置属性类

@ConfigurationProperties(prefix = "my.service")
public class MyServiceProperties {

/**
* 是否启用
*/
private boolean enabled = true;

/**
* 服务名称
*/
private String name = "default";

/**
* 超时时间(毫秒)
*/
private int timeout = 5000;

/**
* 重试次数
*/
private int retry = 3;

// getter/setter
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }

public String getName() { return name; }
public void setName(String name) { this.name = name; }

public int getTimeout() { return timeout; }
public void setTimeout(int timeout) { this.timeout = timeout; }

public int getRetry() { return retry; }
public void setRetry(int retry) { this.retry = retry; }
}

#

3. 创建核心服务类

public class MyService {

private final MyServiceProperties properties;

public MyService(MyServiceProperties properties) {
this.properties = properties;
}

public String sayHello(String name) {
return String.format("[%s] Hello, %s!", properties.getName(), name);
}

public void executeWithRetry(Runnable task) {
int attempts = 0;
while (attempts < properties.getRetry()) {
try {
task.run();
return;
} catch (Exception e) {
attempts++;
if (attempts >= properties.getRetry()) {
throw new RuntimeException("重试耗尽", e);
}
}
}
}
}

#

4. 创建自动配置类

@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(prefix = "my.service", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyServiceProperties.class)
public class MyServiceAutoConfiguration {

private final MyServiceProperties properties;

public MyServiceAutoConfiguration(MyServiceProperties properties) {
this.properties = properties;
}

@Bean
@ConditionalOnMissingBean // 用户定义了则优先使用用户的
public MyService myService() {
return new MyService(properties);
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "my.service", name = "health-check", havingValue = "true")
public MyHealthIndicator myHealthIndicator(MyService myService) {
return new MyHealthIndicator(myService);
}
}

#

5. 配置 spring.factories

# src/main/resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.MyServiceAutoConfiguration

#

6. 配置提示元数据

// src/main/resources/META-INF/additional-spring-configuration-metadata.json
{
"properties": [
{
"name": "my.service.enabled",
"type": "java.lang.Boolean",
"description": "是否启用 MyService",
"defaultValue": true
},
{
"name": "my.service.name",
"type": "java.lang.String",
"description": "服务名称"
},
{
"name": "my.service.timeout",
"type": "java.lang.Integer",
"description": "超时时间(毫秒)",
"defaultValue": 5000
}
]
}

完整项目结构

my-service-spring-boot-starter/
├── pom.xml
└── src/
└── main/
├── java/
│ └── com/example/
│ ├── MyService.java
│ ├── MyServiceProperties.java
│ ├── MyHealthIndicator.java
│ └── autoconfigure/
│ └── MyServiceAutoConfiguration.java
└── resources/
└── META-INF/
├── spring.factories
└── additional-spring-configuration-metadata.json

使用 Starter

#

引入依赖

<dependency>
<groupId>com.example</groupId>
<artifactId>my-service-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>

#

配置文件

my:
service:
enabled: true
name: myApp
timeout: 10000
retry: 5

#

注入使用

@Service
public class BusinessService {
@Autowired
private MyService myService;

public void doSomething() {
String result = myService.sayHello("World");
System.out.println(result);
}
}

高级特性

#

条件装配

@Configuration
public class MyServiceAutoConfiguration {

// 当 classpath 存在 Redis 时
@Bean
@ConditionalOnClass(RedisTemplate.class)
public MyCacheService redisCacheService(RedisTemplate<String, String> redisTemplate) {
return new RedisCacheService(redisTemplate);
}

// 当不存在 Redis 时使用本地缓存
@Bean
@ConditionalOnMissingClass("org.springframework.data.redis.core.RedisTemplate")
public MyCacheService localCacheService() {
return new LocalCacheService();
}
}

#

多配置类

@Configuration
public class MyServiceAutoConfiguration {

@Configuration
@ConditionalOnWebApplication
public static class WebConfiguration {
@Bean
public MyWebInterceptor myWebInterceptor() {
return new MyWebInterceptor();
}
}

@Configuration
@ConditionalOnNotWebApplication
public static class NonWebConfiguration {
@Bean
public MyCliRunner myCliRunner() {
return new MyCliRunner();
}
}
}

测试 Starter

@SpringBootTest(classes = TestApplication.class)
public class MyServiceAutoConfigurationTest {

@Autowired
private MyService myService;

@Autowired
private MyServiceProperties properties;

@Test
public void testServiceCreated() {
assertNotNull(myService);
}

@Test
public void testPropertiesLoaded() {
assertEquals("myApp", properties.getName());
assertEquals(10000, properties.getTimeout());
}
}

@SpringBootApplication
@EnableConfigurationProperties(MyServiceProperties.class)
class TestApplication {
}

发布到 Maven 仓库

<distributionManagement>
<repository>
<id>releases</id>
<url>http://nexus.example.com/repository/maven-releases/</url>
</repository>
</distributionManagement>
mvn clean deploy

总结

开发 Spring Boot Starter 的关键步骤:

  1. 创建项目:引入 spring-boot-autoconfigure
  2. 定义属性:@ConfigurationProperties
  3. 实现功能:核心服务类
  4. 自动配置:@Configuration + 条件注解
  5. 注册配置:META-INF/spring.factories
  6. IDE 提示:配置元数据

自定义 Starter 可以将团队的公共能力沉淀为标准化组件,提高开发效率和代码复用。

核心要点

  1. 日志级别设置:根据环境设置合适的级别

  2. 日志格式配置:添加 traceId 便于链路追踪

  3. 日志输出:控制台输出和文件输出的配置

  4. 日志归档:设置滚动策略和保留时间

总结

日志是排查问题的生命线,合理配置日志可以提升排查效率。在实际项目中,结合 ELK 等工具搭建日志系统,可以更好地管理和分析日志。


   转载规则


《SpringBoot Starter自定义开发》 小乐 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录