Spring Boot 自定义 Starter
Spring Boot Starter
什么是 Starter
Starter 是 Spring Boot 提供的一种依赖管理机制,它将一组相关的依赖打包在一起,让开发者只需引入一个依赖即可获得完整的功能支持。
以常用的 spring-boot-starter-web 为例,我们只需在 pom.xml 中添加一行依赖声明,即可获得构建 Web 应用所需的全部组件。
Starter 的结构分析
打开本地 Maven 仓库中的 ~/.m2/repository/org/springframework/boot/spring-boot-starter-web/4.0.1,可以看到以下文件结构:
.
├── _remote.repositories
├── spring-boot-starter-web-4.0.1.jar
├── spring-boot-starter-web-4.0.1.jar.sha1
├── spring-boot-starter-web-4.0.1.pom
└── spring-boot-starter-web-4.0.1.pom.sha1
查看其 pom 文件,会发现它实际上聚合了多个子依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jackson</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-http-converter</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-webmvc</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
解压 JAR 包后,内容仅有:
├── META-INF
│ ├── LICENSE.txt
│ ├── MANIFEST.MF
│ └── NOTICE.txt
这说明 Starter 本身只是一个空壳,它的核心作用是统一管理依赖及其版本,从而简化开发配置流程。
真正的业务逻辑在哪里?
既然 Starter 只是依赖聚合,那实际的功能代码在哪里呢?答案是 Auto-Configure 模块。
以 spring-boot-http-converter 为例,打开其 pom 文件:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>4.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>7.0.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
解压其 JAR 包,可以看到完全不同的结构:
.
├── META-INF
│ ├── additional-spring-configuration-metadata.json
│ ├── LICENSE.txt
│ ├── MANIFEST.MF
│ ├── NOTICE.txt
│ ├── spring
│ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ ├── spring-autoconfigure-metadata.properties
│ ├── spring-configuration-metadata.json
│ └── spring.factories # 旧版自动配置入口
└── org
└── springframework
└── boot
└── http
└── converter
└── autoconfigure
├── ClientHttpMessageConvertersCustomizer.class
├── DefaultClientHttpMessageConvertersCustomizer.class
├── DefaultServerHttpMessageConvertersCustomizer.class
└── Jackson2HttpMessageConvertersConfiguration$...class
其中,org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件指定了自动配置类的路径:
org.springframework.boot.http.converter.autoconfigure.Jackson2HttpMessageConvertersConfiguration$Jackson2JsonMessageConvertersCustomizer
小结:Starter = 依赖聚合(空壳) + Auto-Configure(实际业务逻辑 + 自动装配配置)
如何编写自定义 Starter
通过上述分析,我们可以总结出创建 Starter 的核心步骤:
- 编写业务代码:实现所需的功能逻辑
- 创建自动配置类:使用
@Configuration+ 条件注解 - 注册自动配置:在
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中声明配置类路径 - 创建 Starter 模块:作为空依赖聚合,引入 auto-configure 和其他第三方依赖
项目结构
按照 Spring Boot 官方规范,一个完整的自定义 Starter 应包含两个模块:
my-starter-parent/
├── pom.xml # 父 POM
├── say-something-spring-boot-autoconfigure/ # 自动配置模块(包含实际代码)
│ ├── pom.xml
│ └── src/main/
│ ├── java/
│ │ └── com/example/autoconfigure/
│ │ ├── SaySomethingAutoConfiguration.java
│ │ └── SaySomethingService.java
│ └── resources/
│ └── META-INF/
│ └── spring/
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
└── say-something-spring-boot-starter/ # Starter 模块(空壳,仅聚合依赖)
└── pom.xml
模块一:autoconfigure(自动配置模块)
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>my-starter-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>say-something-spring-boot-autoconfigure</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 其他业务所需依赖 -->
</dependencies>
</project>
服务类
package com.example.autoconfigure;
public class SaySomethingService {
private String prefix = "Hello";
public String say(String name) {
return prefix + ", " + name + "!";
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}
自动配置类
package com.example.autoconfigure;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnMissingBean(SaySomethingService.class)
public class SaySomethingAutoConfiguration {
@Bean
public SaySomethingService saySomethingService() {
return new SaySomethingService();
}
}
注册自动配置
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
com.example.autoconfigure.SaySomethingAutoConfiguration
模块二:starter(依赖聚合模块)
这是一个 纯空壳模块,不包含任何代码,只有一个 pom.xml 用于聚合依赖。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
<artifactId>my-starter-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>say-something-spring-boot-starter</artifactId>
<dependencies>
<!-- 引入自动配置模块 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>say-something-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 引入其他第三方依赖(如有需要) -->
<!--
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
-->
</dependencies>
</project>
⚠️ 注意:Starter 模块没有
src目录,打包后的 JAR 只包含META-INF基础信息,与官方 Starter 结构完全一致。
使用自定义 Starter
在其他项目中,只需引入 Starter 模块即可:
<dependency>
<groupId>com.example</groupId>
<artifactId>say-something-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
然后直接注入使用:
@RestController
public class HelloController {
@Autowired
private SaySomethingService saySomethingService;
@GetMapping("/hello")
public String hello(@RequestParam String name) {
return saySomethingService.say(name);
}
}
验证配置是否生效
在 application.properties 中开启调试模式:
debug=true
启动应用后,查看控制台日志,如果出现以下信息则说明自动配置成功:
SaySomethingAutoConfiguration matched:
- @ConditionalOnMissingBean (types: com.example.autoconfigure.SaySomethingService; SearchStrategy: all) did not find any beans (OnBeanCondition)
总结
| 模块 | 职责 | 包含内容 |
|---|---|---|
| starter | 依赖聚合入口 | 仅 pom.xml,无代码 |
| autoconfigure | 自动配置逻辑 | 业务代码 + 配置类 + imports 文件 |
用户只需引入 starter 一个依赖,即可自动获得 autoconfigure 及其所有传递依赖,实现开箱即用。