本节目标:搞清一个 starter 由哪两部分组成,拆开
spring-boot-starter-webmvc看清它拉了哪些依赖,并掌握 4.0 模块化后的命名约定。
适用版本:Spring Boot 4.1.x(Java 21)
7.1 Starter 的组成
第 3 章我们往 pom.xml 里加了这么一行,然后一个能跑 HTTP 的服务就出现了:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
没有人写 Tomcat 的启动代码,没有人注册 DispatcherServlet,也没有人配置 JSON 序列化。这一行依赖是怎么做到「一引就全到位」的?本章的三节顺着一条线走:先读懂官方 starter(本节),再自己造一个(7.2),最后学会在它不生效时怎么查(7.3)。
7.1.1 一个 starter 的两块拼图
把「starter」这个词拆开,它其实是两种东西的组合:
| 拼图 | 职责 | 典型内容 |
|---|---|---|
| 依赖聚合模块 | 把「用某技术所需的一组库」收成一个坐标 | 若干 <dependency>,本身几乎没有代码 |
| 自动配置模块 | 提供「这些库在什么条件下、装配成什么 bean」 | @AutoConfiguration 类、@ConfigurationProperties 类、.imports 清单 |
一个小 starter 可以把两块合并进同一个 jar(7.2 我们就是这么做的);官方的大型 starter 通常拆成两个甚至多个 Maven 模块,让「依赖」和「逻辑」各自独立演进。
判断一个坐标属于哪一块,有个很实用的经验:打开它的 jar,如果里面几乎只有 META-INF,那是依赖聚合模块;如果有 @AutoConfiguration 类,那是自动配置模块。
7.1.2 拆开 spring-boot-starter-webmvc
先看依赖聚合这一块。下面是 4.1.1 版本里 spring-boot-starter-webmvc 的真实依赖树(内容来自该版本的 pom,可以直接在本地仓库里核对):
spring-boot-starter-webmvc 4.1.1
├── spring-boot-starter-jackson
│ ├── spring-boot-starter
│ └── spring-boot-jackson
├── spring-boot-starter-tomcat
│ ├── spring-boot-starter
│ ├── spring-boot-starter-tomcat-runtime
│ └── spring-boot-tomcat
├── spring-boot-http-converter
└── spring-boot-webmvc
├── spring-boot-servlet
├── org.springframework:spring-web 7.0.9
├── org.springframework:spring-webmvc 7.0.9
└── spring-boot-http-converter (runtime)
再把最底层的 spring-boot-starter 也拆开——它是所有 starter 的公共基座:
spring-boot-starter 4.1.1
├── spring-boot-starter-logging # Logback + SLF4J 桥接
├── spring-boot-autoconfigure # 自动配置骨架与条件注解
├── jakarta.annotation-api
└── org.yaml:snakeyaml # 解析 application.yml
看懂这棵树,几个平时「想当然」的问题就有答案了:
- 内嵌 Tomcat 从哪来? 从
spring-boot-starter-tomcat传递进来,不是spring-boot-starter-webmvc直接写的。 - JSON 支持从哪来? 从
spring-boot-starter-jackson。4.x 用 Jackson 3,包名已从com.fasterxml.jackson迁到tools.jackson。 - 为什么能读 YAML? 因为基座
spring-boot-starter里有snakeyaml。 - 为什么 starter 里几乎没有自己的类? 因为它就是个「依赖清单」,逻辑都在
spring-boot-webmvc、spring-boot-tomcat这些技术模块里。
顺带确认一个易混点:
spring-boot-starter-web在 4.1.1 里仍然存在,但它的 pom 描述已经写明「deprecated in favor of spring-boot-starter-webmvc」。新项目一律用spring-boot-starter-webmvc。
7.1.3 为什么拆成「依赖聚合 + 自动配置」
把两块分开,是为了让它们各自解决一个正交的问题:
- 依赖聚合解决「版本」:
spring-boot-starter-webmvc不写任何<version>,版本由spring-boot-dependencies这份 BOM 统一钉死。你引一行,就等于接受了「这一版 Boot 认可的、彼此兼容的一组版本」。 - 自动配置解决「装配」:
spring-boot-webmvc里带着@AutoConfiguration类,在 classpath 上发现对应条件满足时,把DispatcherServlet、RequestMappingHandlerMapping这些 bean 注册好。
如果只有依赖聚合,你引完还得自己写一堆 @Bean;如果只有自动配置,你又得手工对齐每个库的版本。两块拼在一起,才是「引一行就可用」的完整体验。
7.1.4 4.0 模块化后的命名三段式
4.0 最大的破坏性变更就是模块化:原来集中在 spring-boot-autoconfigure 一个模块里的自动配置,被拆散到各技术自己的模块里。拆分遵循一条整齐的命名规则,记住这三段,遇到任何官方 starter 都能反推它的包和模块:
| 角色 | 命名规则 | Tomcat | Jackson |
|---|---|---|---|
| 技术模块 | spring-boot-<tech> | spring-boot-tomcat | spring-boot-jackson |
| 根包 | org.springframework.boot.<tech> | org.springframework.boot.tomcat | org.springframework.boot.jackson |
| 自动配置子包 | org.springframework.boot.<tech>.autoconfigure | ...tomcat.autoconfigure | ...jackson.autoconfigure |
| Starter | spring-boot-starter-<tech> | spring-boot-starter-tomcat | spring-boot-starter-jackson |
| 测试模块 | spring-boot-<tech>-test | — | — |
这个规律在启动日志里能直接看到证据——Tomcat 相关日志的类名,3.x 是 o.s.b.w.embedded.tomcat.TomcatWebServer,4.x 变成了 o.s.boot.tomcat.TomcatWebServer:
2026-10-09T15:42:07.027+08:00 INFO 43496 --- [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2026-10-09T15:42:09.015+08:00 INFO 43496 --- [tomcat-shutdown] o.s.boot.tomcat.GracefulShutdown : Graceful shutdown complete
同一套规律还带来一批 starter 改名。旧名在 4.1.1 里大多还留着(能在 BOM 里搜到),但已废弃,正文与新项目一律用新名:
| 废弃旧名 | 4.x 新名 |
|---|---|
spring-boot-starter-web | spring-boot-starter-webmvc |
spring-boot-starter-aop | spring-boot-starter-aspectj |
spring-boot-starter-oauth2-client | spring-boot-starter-security-oauth2-client |
spring-boot-starter-oauth2-resource-server | spring-boot-starter-security-oauth2-resource-server |
spring-boot-starter-oauth2-authorization-server | spring-boot-starter-security-oauth2-authorization-server |
spring-boot-starter-web-services | spring-boot-starter-webservices |
spring-boot-starter-tomcat(war 部署场景) | spring-boot-starter-tomcat-runtime |
迁移期如果不想逐个改坐标,可以先整体切到过渡用的 spring-boot-starter-classic / spring-boot-starter-test-classic,它们聚合了旧命名的那套依赖。
7.1.5 -test 测试模块的约定
除了 spring-boot-starter-test 这个通用测试 starter,4.x 还给每个技术配了专属测试模块,命名规则同样是三段式的延伸:
模块 spring-boot-<tech>-test
包 org.springframework.boot.<tech>.test
starter spring-boot-starter-<tech>-test
在 BOM 里能看到大量实例:spring-boot-starter-webmvc-test、spring-boot-starter-jackson-test、spring-boot-starter-data-jpa-test、spring-boot-starter-security-test。它们装的是这个技术专用的测试支持——比如对应的测试切片注解、断言工具、测试用配置。写 Web 层测试时,除了通用测试依赖,往往还要引 spring-boot-starter-webmvc-test 才能用上该层专属的测试设施(第 17 章会具体用)。
7.1.6 为什么 starter 不该带 @ComponentScan
这是自定义 starter 时最容易犯、也最难查的错。看下面这个反面教材:
// 反面教材:不要这样写
@AutoConfiguration
@ComponentScan("com.acme")
public class AcmeAutoConfiguration {
// ...
}
问题出在 @ComponentScan 的默认语义:它扫描的是「声明它的那个类所在的包及其子包」。上面这行如果落在 com.acme.spring.boot.autoconfigure,默认会去扫 com.acme.spring.boot.autoconfigure.**;而一旦你把包根写成 com.acme(或某个与应用重叠的命名空间),它就会顺着包树扫进使用方的代码里,把本该由应用自己管理的 @Component、@Configuration 一起拉进容器。
后果是:组件被重复注册、应用自己的扫描策略被打乱、某些 bean 的出现变得「看包名运气」。starter 的设计哲学是只装配自己声明的东西,绝不主动扫描别人的代码。正确做法只有三种:
| 想做的事 | 正确手段 |
|---|---|
| 注册一个 bean | 在 @AutoConfiguration 类里写 @Bean 方法 |
| 引入另一个配置类 | @Import(SomeConfiguration.class) |
| 绑定一组属性 | @EnableConfigurationProperties(AcmeProperties.class) |
记住一句话:starter 里出现的 @ComponentScan,几乎都是 bug。
7.1.7 官方 starter 一览表(按用途分类)
4.1.1 的 BOM 里能搜到 170 个以 spring-boot-starter 开头的坐标(含 -test 变体)。按用途归类,常用的如下:
Web 与视图
| Starter | 用途 |
|---|---|
spring-boot-starter-webmvc | Spring MVC + 内嵌 Tomcat(默认 Web 选择) |
spring-boot-starter-webflux | 响应式 Web |
spring-boot-starter-webclient / -restclient | 声明式 / 命令式 HTTP 客户端 |
spring-boot-starter-websocket | WebSocket |
spring-boot-starter-webservices | Spring Web Services(SOAP) |
spring-boot-starter-thymeleaf / -freemarker / -mustache | 服务端模板引擎 |
数据访问
| Starter | 用途 |
|---|---|
spring-boot-starter-jdbc | 原生 JDBC + HikariCP |
spring-boot-starter-data-jpa | JPA / Hibernate |
spring-boot-starter-data-jdbc | Spring Data JDBC |
spring-boot-starter-data-mongodb | MongoDB |
spring-boot-starter-data-redis | Redis |
spring-boot-starter-data-elasticsearch | Elasticsearch |
spring-boot-starter-jooq | jOOQ |
安全
| Starter | 用途 |
|---|---|
spring-boot-starter-security | Spring Security 核心 |
spring-boot-starter-security-oauth2-client | OAuth2 客户端 |
spring-boot-starter-security-oauth2-resource-server | OAuth2 资源服务器 |
spring-boot-starter-security-oauth2-authorization-server | 授权服务器 |
消息与集成
| Starter | 用途 |
|---|---|
spring-boot-starter-amqp | RabbitMQ / AMQP |
spring-boot-starter-kafka | Kafka |
spring-boot-starter-jms / -activemq / -artemis | JMS 与各家实现 |
spring-boot-starter-integration | Spring Integration |
运维与观测
| Starter | 用途 |
|---|---|
spring-boot-starter-actuator | 健康检查、指标、端点 |
spring-boot-starter-micrometer-metrics | Micrometer 指标 |
spring-boot-starter-opentelemetry | OpenTelemetry(4.0 新增) |
spring-boot-starter-zipkin | 链路追踪导出 |
工具、任务与数据库迁移
| Starter | 用途 |
|---|---|
spring-boot-starter-validation | Bean Validation |
spring-boot-starter-aspectj | AOP(旧名 -aop) |
spring-boot-starter-cache | 缓存抽象 |
spring-boot-starter-batch | 批处理 |
spring-boot-starter-quartz | 定时任务 |
spring-boot-starter-flyway / -liquibase | 数据库迁移(4.0 起必须显式引 starter) |
spring-boot-starter-grpc-client / -grpc-server | Spring gRPC(4.1 新增) |
注意最后一行里的迁移类:4.0 之前,只要 classpath 上有 Flyway 的库就会被自动配置;4.0 起必须显式引
spring-boot-starter-flyway。这类「以前不用 starter、现在必须加」的变化,是升级时最容易被忽略的一类。
7.1.8 一个常见误解:starter 不是「库」
初学者常把 starter 当成「某个功能的实现库」,于是问出「spring-boot-starter-webmvc 和 spring-webmvc 有什么区别」。答案是它们根本不在一个层级:
spring-webmvc(org.springframework:spring-webmvc)是实现,装着DispatcherServlet这些真正的代码。spring-boot-starter-webmvc是入口,它把spring-webmvc连同 Tomcat、Jackson、自动配置一起拉进来,并保证版本互相兼容。
所以 starter 本身可以「没有一行 Java 代码」——它的价值在于替你做了正确的依赖决策。理解了这一点,7.2 里我们自己写的 starter,重点也就会放在「选对依赖 + 写对自动配置」,而不是写多少业务代码。
7.1.9 怎么查一个 starter 到底拉了什么
7.1.2 那棵树不是背出来的,是查出来的。以后遇到「引了这个 starter 却出现了意外的库」,用下面任意一种方式复现:
方式一:Maven 依赖树。 在项目根目录执行:
mvn dependency:tree -Dincludes=org.springframework.boot:*
输出会把 org.springframework.boot 组下的所有传递依赖按层级列出来,7.1.2 的结构就是它的简化版。只想看某个 starter 的直接依赖时,把 -Dincludes 换成对应坐标即可。
方式二:IDE 的依赖视图。 IntelliJ IDEA 右侧 Maven 面板里展开 Dependencies,能折叠展开整棵树;比命令行更直观,还能直接看到「某个依赖是被谁引入的」。
方式三:直接读 pom。 每个 starter 的 jar 里都带一份 .pom,用压缩工具打开 META-INF/maven/.../pom.xml 就能看到它的 <dependencies>。这也是本节依赖树的数据来源。
一个典型用途:项目里同时出现了 Logback 和 Log4j2,日志格式诡异。查依赖树发现是某个 starter 传递引入了 spring-boot-starter-logging,于是改用 spring-boot-starter-log4j2 并排除默认日志——这类排查的第一步,永远是先把依赖树看清楚。
小结
- 一个 starter 由两块拼图组成:依赖聚合模块(选对一组库与版本)与自动配置模块(按条件装配 bean);小 starter 可合并进一个 jar,官方大型 starter 常拆成多个模块。
spring-boot-starter-webmvc的真实依赖是spring-boot-starter-jackson+spring-boot-starter-tomcat+spring-boot-http-converter+spring-boot-webmvc,所有 starter 的基座是spring-boot-starter。- 4.0 模块化的命名三段式:模块
spring-boot-<tech>、包org.springframework.boot.<tech>、starterspring-boot-starter-<tech>,测试模块为spring-boot-<tech>-test。 - 一批 starter 在 4.x 改名(如
-web→-webmvc、-aop→-aspectj),旧名保留但已废弃。 - starter 里不能出现
@ComponentScan,它会扫进使用方的包;应改用@Bean、@Import、@EnableConfigurationProperties。
读懂了官方 starter 的骨架,下一步就是自己动手造一个——这会逼你面对 7.1 里提到的每一个约定:依赖怎么选、自动配置类怎么写、.imports 文件放哪。
阅读导航:上一节:6.3 外部化配置的优先级 · 下一节:7.2 写一个自定义 Starter 。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。