大家好,我是Java1234_小锋老师。

先说结论
Spring Boot 4.0 已经移除了对 Undertow 的官方支持,spring-boot-starter-undertow 不再随 Spring Boot 4 发布,内嵌 Undertow 的自动配置也被一并删除。
严格来说,这次变化并不只是给 Undertow 加上一个"未来可能删除"的弃用标记,而是直接移除支持。如果现有项目使用 Spring Boot 3.x + Undertow,那么升级到 Spring Boot 4.0 时不能只改版本号,还需要把 Web 容器迁移到 Tomcat 或 Jetty。
好消息是,大多数普通 Spring MVC 项目不需要改业务代码,主要调整依赖并完成一轮回归测试即可。
为什么不再支持 Undertow
Spring Boot 4 基于 Jakarta EE 11,并把 Servlet API 的基线提升到了 Servlet 6.1。Spring Boot 4 发布时,Undertow 尚未提供可供 Spring Boot 稳定集成的 Servlet 6.1 版本,因此官方选择删除 Undertow Starter、自动配置和内嵌服务器支持。
这条变化可以简单理解为:
#mermaid-svg-EXkGxCQvQ0WAnwzq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EXkGxCQvQ0WAnwzq .error-icon{fill:#552222;}#mermaid-svg-EXkGxCQvQ0WAnwzq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EXkGxCQvQ0WAnwzq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .marker.cross{stroke:#333333;}#mermaid-svg-EXkGxCQvQ0WAnwzq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EXkGxCQvQ0WAnwzq p{margin:0;}#mermaid-svg-EXkGxCQvQ0WAnwzq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .cluster-label text{fill:#333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .cluster-label span{color:#333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .cluster-label span p{background-color:transparent;}#mermaid-svg-EXkGxCQvQ0WAnwzq .label text,#mermaid-svg-EXkGxCQvQ0WAnwzq span{fill:#333;color:#333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .node rect,#mermaid-svg-EXkGxCQvQ0WAnwzq .node circle,#mermaid-svg-EXkGxCQvQ0WAnwzq .node ellipse,#mermaid-svg-EXkGxCQvQ0WAnwzq .node polygon,#mermaid-svg-EXkGxCQvQ0WAnwzq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EXkGxCQvQ0WAnwzq .rough-node .label text,#mermaid-svg-EXkGxCQvQ0WAnwzq .node .label text,#mermaid-svg-EXkGxCQvQ0WAnwzq .image-shape .label,#mermaid-svg-EXkGxCQvQ0WAnwzq .icon-shape .label{text-anchor:middle;}#mermaid-svg-EXkGxCQvQ0WAnwzq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EXkGxCQvQ0WAnwzq .rough-node .label,#mermaid-svg-EXkGxCQvQ0WAnwzq .node .label,#mermaid-svg-EXkGxCQvQ0WAnwzq .image-shape .label,#mermaid-svg-EXkGxCQvQ0WAnwzq .icon-shape .label{text-align:center;}#mermaid-svg-EXkGxCQvQ0WAnwzq .node.clickable{cursor:pointer;}#mermaid-svg-EXkGxCQvQ0WAnwzq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .arrowheadPath{fill:#333333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EXkGxCQvQ0WAnwzq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EXkGxCQvQ0WAnwzq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EXkGxCQvQ0WAnwzq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EXkGxCQvQ0WAnwzq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EXkGxCQvQ0WAnwzq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EXkGxCQvQ0WAnwzq .cluster text{fill:#333;}#mermaid-svg-EXkGxCQvQ0WAnwzq .cluster span{color:#333;}#mermaid-svg-EXkGxCQvQ0WAnwzq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EXkGxCQvQ0WAnwzq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EXkGxCQvQ0WAnwzq rect.text{fill:none;stroke-width:0;}#mermaid-svg-EXkGxCQvQ0WAnwzq .icon-shape,#mermaid-svg-EXkGxCQvQ0WAnwzq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EXkGxCQvQ0WAnwzq .icon-shape p,#mermaid-svg-EXkGxCQvQ0WAnwzq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EXkGxCQvQ0WAnwzq .icon-shape .label rect,#mermaid-svg-EXkGxCQvQ0WAnwzq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EXkGxCQvQ0WAnwzq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EXkGxCQvQ0WAnwzq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EXkGxCQvQ0WAnwzq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 兼容
当时未满足要求
Spring Boot 4.0
Jakarta EE 11
Servlet 6.1 基线
内嵌容器是否兼容
Tomcat / Jetty
移除 Undertow 官方支持
这不代表 Undertow 本身"不能用了"或"性能不好"。问题的核心是版本基线、发布时间以及长期维护成本,而不是一次服务器性能排名。
升级后会遇到什么问题
假设 Spring Boot 3 项目原来这样引入 Undertow:
xml
<!-- Spring Boot 3.x:排除默认 Tomcat,改用 Undertow -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
直接把 Spring Boot 升级到 4.0 后,Maven 会因为找不到对应版本的 spring-boot-starter-undertow 而构建失败。即使手动拼装 Undertow 依赖,原来由 Spring Boot 提供的自动配置类和属性适配也已经不存在,维护难度会明显增加。
方案一:切换到 Tomcat
Tomcat 仍然是最省心的选择,也是 Spring MVC 默认使用的内嵌容器。Spring Boot 4 对 Starter 做了进一步拆分,新的 MVC 项目建议直接使用 spring-boot-starter-webmvc:
xml
<!-- Spring Boot 4:默认包含内嵌 Tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
迁移时删除 spring-boot-starter-undertow,同时去掉对 spring-boot-starter-tomcat 的排除即可。Controller 通常不需要修改:
java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 服务状态接口。
*/
@RestController
public class HealthController {
/**
* 返回当前服务状态,用于迁移后的连通性检查。
*
* @return 服务状态
*/
@GetMapping("/health")
public String health() {
return "Spring Boot 4 is running";
}
}
方案二:切换到 Jetty
如果团队原本就熟悉 Jetty,或者测试后发现它更符合项目需求,可以排除默认 Tomcat,再引入 Jetty:
xml
<!-- Spring Boot 4:Spring MVC + Jetty -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
不要只凭"听说哪个容器更快"来决定。真实项目中的过滤器、上传下载、长连接、线程配置和监控体系都会影响结果。先用接近生产环境的流量做压测,再决定是否需要从默认 Tomcat 切换到 Jetty。
迁移时别忘了这些检查
容器替换看起来只是改几行 pom.xml,但以下内容很容易被遗漏:
- 检查 Java 版本:Spring Boot 4 最低要求 Java 17,官方建议优先使用较新的 LTS 版本。
- 搜索 Undertow 专属代码 :例如
io.undertow.*、UndertowServletWebServerFactory和 Undertow 自定义 Handler。 - 清理专属配置 :删除
server.undertow.*,再根据实际压测结果配置 Tomcat 或 Jetty。 - 回归 Web 功能:重点测试文件上传、静态资源、错误页、压缩、HTTPS、WebSocket 和反向代理转发。
- 观察运行指标:对比迁移前后的启动时间、堆内存、线程数、吞吐量和 P99 响应时间。
可以先用 Maven 检查依赖树,确认 Undertow 已经彻底移除:
bash
# 检查依赖树中是否还存在 Undertow
./mvnw dependency:tree -Dincludes=io.undertow
# 启动应用并进行基础回归验证
./mvnw spring-boot:run
还能继续使用 Undertow 吗
理论上可以自行维护集成层,或者等待社区提供适配 Spring Boot 4 的 Starter,但这已经不是 Spring Boot 官方开箱即用的能力。即使新版 Undertow 后续支持了 Servlet 6.1,也不等于官方 Starter 会自动回来。
Spring Boot 团队后来进一步说明,不计划重新引入官方 Undertow 支持;如果社区需求足够强,可以由社区维护独立模块。因此,对普通业务项目来说,升级时按 Tomcat 或 Jetty 进行规划更稳妥。只有在内存限制、既有基础设施等因素确实要求 Undertow 时,才值得承担第三方集成的版本兼容和长期维护成本。
写在最后
Spring Boot 4.0 移除 Undertow,表面上是少了一个内嵌服务器选项,背后其实是整个技术栈向 Jakarta EE 11 和 Servlet 6.1 迈进的结果。
如果你的项目没有使用 Undertow,这次变化基本无感;如果正在使用,也不必过度紧张。先清理 Undertow 专属依赖与配置,切换到 Tomcat 或 Jetty,再通过压测和回归测试验证,通常就是一条清晰、可控的升级路线。