今天星期六,继续卷spring boot 3.x。
在 Spring Boot 3.x 中,自定义 Starter 是封装和共享通用功能、实现“约定优于配置”理念的强大机制。通过创建自己的 Starter,您可以将特定的依赖、自动配置和默认设置打包,从而简化多个项目的集成和开发过程。本文将详细介绍在 Spring Boot 3.x 中创建自定义 Starter 的完整流程,并重点阐述其与旧版本的区别及最佳实践。
核心概念:Starter 的作用
Spring Boot Starter 主要包含以下两个核心部分:
- 依赖管理:一个 xxx-spring-boot-starter 的 pom.xml 文件,它传递性地引入了所需的所有依赖。
- 自动配置:一个 xxx-spring-boot-autoconfigure 模块,其中包含了自动配置类,这些类会在特定条件下(例如,类路径上存在某个类)自动注册 Spring Beans。
从 Spring Boot 2.x 到 3.x 的关键变化
Spring Boot 3.x 带来了几个重要的变化,对自定义 Starter 的创建产生了直接影响:
- Java 17 基线:Spring Boot 3.0 要求至少使用 Java 17。
- 迁移到 Jakarta EE:所有依赖项已从 Java EE 迁移到 Jakarta EE,这意味着包名从 javax.* 变为 jakarta.*。[1]
- 自动配置注册方式变更:这是最核心的变化。在 Spring Boot 2.7 之前,自动配置类需要在 META-INF/spring.factories 文件中通过 org.springframework.boot.autoconfigure.EnableAutoConfiguration键来注册。从 Spring Boot 2.7 开始,引入了一种新的方式,并最终在 Spring Boot 3.x 中成为唯一支持的方式:在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中列出自动配置类的全限定名。[2]
创建自定义 Starter 的步骤
创建一个功能完备的自定义 Starter 通常遵循以下步骤。我们将以一个简单的“问候服务”为例,该服务可以根据配置输出不同的问候语。
1. 项目结构规划
最佳实践建议将 Starter 分为两个模块:
- greeting-spring-boot-autoconfigure:包含核心的自动配置逻辑。
- greeting-spring-boot-starter:一个“空”的 Starter,主要用于管理依赖,它会引入 autoconfigure 模块和其他必要的库。[3]
这种分离的好处在于,autoconfigure 模块可以被更灵活地包含在其他项目中,而不仅仅是通过 Starter。
2. 创建autoconfigure模块
a. 添加核心依赖
在
greeting-spring-boot-autoconfigure 模块的 pom.xml 中,引入 spring-boot-starter 和 spring-boot-autoconfigure:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 其他业务逻辑需要的依赖 -->
</dependencies>
b. 创建配置属性类 (Properties)
创建一个类来接收来自 application.properties 或 application.yml 的自定义配置。
package com.example.greeting.autoconfigure;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "greeting")
public class GreetingProperties {
private String name = "World";
private String message = "Hello";
// Getters and Setters
}
c. 实现业务逻辑服务
创建一个简单的服务类,它将使用上述配置属性。
package com.example.greeting.autoconfigure;
public class GreetingService {
private final GreetingProperties properties;
public GreetingService(GreetingProperties properties) {
this.properties = properties;
}
public String greet() {
return properties.getMessage() + ", " + properties.getName() + "!";
}
}
d. 创建自动配置类 (AutoConfiguration)
这是 Starter 的核心,它会根据条件创建并注册 GreetingService Bean。
package com.example.greeting.autoconfigure;
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;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(GreetingProperties.class)
@ConditionalOnProperty(prefix = "greeting", name = "enabled", havingValue = "true", matchIfMissing = true)
public class GreetingAutoConfiguration {
private final GreetingProperties properties;
public GreetingAutoConfiguration(GreetingProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public GreetingService greetingService() {
return new GreetingService(properties);
}
}
- @Configuration: 声明这是一个配置类。
- @EnableConfigurationProperties: 启用 GreetingProperties 类与配置文件的绑定。
- @ConditionalOnProperty: 允许通过配置来启用或禁用此自动配置。
- @Bean 和 @ConditionalOnMissingBean: 只有当应用上下文中不存在 GreetingService 类型的 Bean 时,才会创建这个默认的 Bean,这允许用户自定义覆盖。
e. 注册自动配置类
在
src/main/resources/META-INF/spring/ 目录下创建一个名为
org.springframework.boot.autoconfigure.AutoConfiguration.imports 的文件。文件内容是自动配置类的全限定名:
com.example.greeting.autoconfigure.GreetingAutoConfiguration
3. 创建starter模块
a. 添加依赖
在
greeting-spring-boot-starter 模块的 pom.xml 中,添加对 autoconfigure 模块的依赖:
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>greeting-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
这个 Starter 的主要职责就是提供一个简单的依赖入口,将所有需要的模块聚合起来。
4. 安装和使用自定义 Starter
- 在本地 Maven 仓库中安装你的 Starter 项目:mvn clean install。
- 在需要使用该 Starter 的 Spring Boot 项目中,添加依赖:
<dependency>
<groupId>com.example</groupId>
<artifactId>greeting-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
- 在 application.properties 中进行配置:
greeting.name=Spring Boot 3
greeting.message=Welcome
- 现在,你可以在你的应用中注入并使用 GreetingService 了:
@RestController
public class MyControlle
{
private final GreetingService greetingService;
public MyController(GreetingService greetingService)
{
this.greetingService = greetingService;
}
@GetMapping("/greet")
public String greet()
{
return greetingService.greet(); // 输出 "Welcome, Spring Boot 3!" }
}
最佳实践
- 命名规范:官方 Starter 的命名格式为 spring-boot-starter-xxx。自定义 Starter 推荐使用 xxx-spring-boot-starter 的格式,以区分官方和第三方 Starter。
- 条件化配置:充分利用 @Conditional 注解(如 @ConditionalOnClass、@ConditionalOnProperty、@ConditionalOnMissingBean 等),使你的自动配置更加灵活和健壮。
- 配置元数据:为了在 IDE 中提供良好的代码提示和自动完成,可以添加 spring-boot-configuration-processor 依赖。它会自动生成 META-INF/spring-configuration-metadata.json 文件。
- AOT 和 GraalVM 支持:Spring Boot 3 引入了对 AOT(Ahead-Of-Time)编译和 GraalVM 原生镜像的增强支持。如果你的 Starter 需要支持原生镜像,可能需要提供额外的运行时提示(Runtime Hints)。