Tomcat、Jetty、Undertow 三个 Servlet 容器有什么区别?怎么选?
简化版
**Tomcat、Jetty、Undertow 都是「Servlet 容器(Web 服务器)」——都实现了 Servlet 规范、能跑 Java Web 应用,是 Spring Boot 支持的三种内嵌容器。**区别:① Tomcat(最主流)——Apache 出品,生态最成熟、文档最全、社区最大、最稳定,是 Spring Boot 默认的容器,功能全面(也因此稍重);② Jetty——轻量、灵活、启动快,历史悠久,适合嵌入式场景(被很多产品内嵌,如 Google App Engine 早期、Hadoop),模块化设计好;③ Undertow——JBoss/Red Hat 出品,性能高、内存占用低、非阻塞,基于 XNIO,轻量高性能,适合高并发和资源受限场景。怎么选:大多数场景用 Tomcat(默认、成熟、生态好,没特殊需求就用它);追求极致性能/低内存/高并发用 Undertow;需要轻量嵌入/灵活定制用 Jetty。在 Spring Boot 里切换很简单:排除默认的 spring-boot-starter-tomcat、引入 spring-boot-starter-jetty 或 spring-boot-starter-undertow 即可(代码不用改)。核心:三者都是 Servlet 容器,Tomcat 主流成熟(默认)、Jetty 轻量灵活、Undertow 高性能低内存;按需求选,切换只改依赖。
详细版
三者对比:
| 维度 | Tomcat | Jetty | Undertow |
|---|---|---|---|
| 出品 | Apache | Eclipse | Red Hat/JBoss |
| 定位 | 主流、成熟、全面 | 轻量、灵活、嵌入式 | 高性能、低内存 |
| 生态 | 最成熟(文档/社区最全) | 成熟 | 较新 |
| 性能 | 好 | 好 | 更好(非阻塞、低内存) |
| 内存 | 一般 | 较低 | 最低 |
| Spring Boot | 默认 | 可选 | 可选 |
| 适用 | 大多数场景(默认) | 轻量嵌入、灵活定制 | 高并发、资源受限 |
<!-- Spring Boot 默认用 Tomcat(spring-boot-starter-web 自带)-->
<!-- 切换到 Undertow:排除 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> <!-- 排除 Tomcat -->
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId> <!-- 引入 Undertow -->
</dependency>
<!-- 切换到 Jetty 同理:排除 Tomcat,引入 spring-boot-starter-jetty -->
⚠️ 三个容器的选择,本质是「成熟度/生态 vs 性能/资源」的权衡,但对大多数应用来说 Tomcat 就是最优选(别为了性能盲目换)。Tomcat 是 Spring Boot 的默认容器,不是没有原因的——它生态最成熟(遇到问题最容易找到答案、文档最全、社区最大、被验证得最多、最稳定),功能全面。虽然 Undertow 在 benchmark 上性能更好、内存更低,但对大多数业务应用(不是极致性能场景),容器往往不是瓶颈(瓶颈通常在数据库、业务逻辑、网络),换容器带来的性能提升可能微乎其微,却损失了 Tomcat 的成熟生态。所以除非你确实是高并发、资源受限、或对内存/性能有极致要求,否则用默认的 Tomcat 就好。真要换,Undertow 是高性能低内存的首选(非阻塞、基于 XNIO)、Jetty 适合轻量嵌入和灵活定制。而且在 Spring Boot 里切换成本极低(只改依赖、代码不动),可以先用 Tomcat、真遇到性能问题再考虑换(并压测验证)。
完整版教学
一、三者的共同点:Servlet 容器
先理解三者的共同点:
三者都是 Servlet 容器(Web 服务器):
① 都实现了 Servlet 规范(Servlet/Filter/Listener、Session 等)
② 都能跑 Java Web 应用(war 包、Spring Boot 应用)
③ 都是 Spring Boot 支持的内嵌容器(可选其一)
Servlet 容器的职责:
- 监听端口、接受 HTTP 请求
- 把请求解析成 HttpServletRequest、封装 HttpServletResponse
- 管理 Servlet 生命周期、线程池处理请求
- 支持 Session、Filter、Listener 等
所以它们是"同类产品"(都是 Servlet 容器):
→ 都能干同样的活(跑 Java Web 应用)
→ 区别在实现、性能、生态、定位
在 Spring Boot 里可互换:
同一套代码,换内嵌容器(改依赖),行为基本不变
→ 因为都实现 Servlet 规范、Spring Boot 抽象了容器
所以三者都是 Servlet 容器,功能上等价,区别在实现和特性
三者的共同点——都是 Servlet 容器(Web 服务器):① 都实现 Servlet 规范、② 都能跑 Java Web 应用、③ 都是 Spring Boot 支持的内嵌容器。Servlet 容器的职责:监听端口接受 HTTP 请求、解析成 HttpServletRequest、管理 Servlet 生命周期、线程池处理、支持 Session/Filter/Listener。它们是同类产品(都能跑 Java Web 应用、区别在实现/性能/生态/定位)。在 Spring Boot 里可互换(同套代码换容器改依赖、行为基本不变)。理解「三者都是 Servlet 容器:都实现 Servlet 规范/都跑 Java Web 应用/都是 Spring Boot 内嵌容器;职责监听端口/解析请求/管理 Servlet/线程池;功能等价区别在实现性能生态;Spring Boot 里可互换」,就理解了三者的共同点。
二、Tomcat:主流成熟
Tomcat——最主流、最成熟,Spring Boot 默认:
Tomcat(Apache Tomcat):
出品:Apache 软件基金会
地位:最主流的 Servlet 容器,Spring Boot 默认
特点:
① 生态最成熟——
文档最全、社区最大、被验证最多、最稳定
→ 遇到问题最容易找到答案
② 功能全面——
完整的 Servlet/JSP 实现、集群、各种连接器
→ 但也因此稍重(功能多)
③ 广泛使用——
大量企业级应用用它,久经考验
为什么是 Spring Boot 默认:
① 最成熟稳定,风险最低
② 生态最好,遇到问题好解决
③ 大多数场景够用(容器很少是瓶颈)
→ 默认给最稳妥的选择
连接器(IO 模型):
Tomcat 支持 NIO(默认)、NIO2、APR
→ NIO 多路复用,性能不错(见 connector-io-model 题)
适用:
大多数场景(默认、成熟、生态好)
→ 没特殊需求就用 Tomcat
所以 Tomcat 主流成熟、Spring Boot 默认、大多数场景首选
Tomcat(Apache 出品)——最主流、Spring Boot 默认。特点:① 生态最成熟(文档最全、社区最大、最稳定、遇问题好解决)、② 功能全面(完整 Servlet/JSP、集群、连接器,也因此稍重)、③ 广泛使用久经考验。为什么默认:最成熟稳定风险低、生态最好、大多数场景够用(容器很少是瓶颈)。连接器支持 NIO(默认)/NIO2/APR。适用大多数场景(没特殊需求就用)。理解「Tomcat 主流成熟 Spring Boot 默认:生态最成熟(文档社区最全最稳定)/功能全面(稍重)/广泛使用;为什么默认:成熟稳定+生态好+大多数够用(容器很少是瓶颈);大多数场景首选」,就掌握了 Tomcat。
三、Jetty:轻量灵活
Jetty——轻量、灵活、适合嵌入式:
Jetty(Eclipse Jetty):
出品:Eclipse 基金会
定位:轻量、灵活、嵌入式
特点:
① 轻量——比 Tomcat 更小、启动快
② 模块化——设计模块化好,能按需裁剪
③ 灵活——容易嵌入、定制
④ 历史悠久——被很多产品内嵌
(Google App Engine 早期、Hadoop、各种中间件)
为什么适合嵌入式:
轻量 + 模块化 + 易嵌入
→ 很多产品把 Jetty 内嵌进自己(作为 HTTP 服务)
→ "嵌入式 Web 服务器"场景 Jetty 是老牌选择
对比 Tomcat:
Jetty 更轻、更灵活(适合嵌入、定制)
Tomcat 更全面、生态更成熟(企业应用)
适用:
① 需要轻量嵌入(把 Web 服务嵌入自己的应用/产品)
② 需要灵活定制、模块化裁剪
③ 资源受限、要求启动快
所以 Jetty 轻量灵活、适合嵌入式和定制场景
Jetty(Eclipse 出品)——轻量、灵活、适合嵌入式。特点:① 轻量(比 Tomcat 小、启动快)、② 模块化(设计好、能按需裁剪)、③ 灵活(易嵌入定制)、④ 历史悠久(被很多产品内嵌,如 Hadoop、各种中间件)。为什么适合嵌入式:轻量+模块化+易嵌入(很多产品把 Jetty 内嵌作为 HTTP 服务)。对比 Tomcat:Jetty 更轻更灵活(嵌入定制)、Tomcat 更全面生态成熟(企业应用)。适用:轻量嵌入、灵活定制、资源受限启动快。理解「Jetty 轻量灵活嵌入式:轻量(比 Tomcat 小启动快)/模块化(按需裁剪)/易嵌入定制/历史悠久被很多产品内嵌;适合轻量嵌入+灵活定制+资源受限」,就掌握了 Jetty。
四、Undertow:高性能低内存
Undertow——高性能、低内存、非阻塞:
Undertow(Red Hat/JBoss):
出品:Red Hat(JBoss)
定位:高性能、低内存、非阻塞
特点:
① 高性能——基于 XNIO(非阻塞 IO),性能好
② 低内存——内存占用比 Tomcat/Jetty 低
③ 非阻塞——支持非阻塞 IO、异步
④ 轻量——核心很小
⑤ 灵活——可以只用 HTTP 核心(不用 Servlet),做轻量 HTTP 服务
为什么性能好、内存低:
① 基于 XNIO(非阻塞 IO 框架)
② 精简设计、少额外开销
→ benchmark 上性能常优于 Tomcat/Jetty、内存更低
对比 Tomcat:
Undertow 性能更好、内存更低
Tomcat 生态更成熟、更稳定(久经验证)
适用:
① 高并发(性能敏感)
② 资源受限(内存少,如容器化、微服务)
③ 追求极致性能/低内存
注意:
Undertow 较新,生态不如 Tomcat(遇到问题资料相对少)
所以 Undertow 高性能低内存、适合高并发和资源受限场景
Undertow(Red Hat/JBoss 出品)——高性能、低内存、非阻塞。特点:① 高性能(基于 XNIO 非阻塞 IO)、② 低内存(占用比 Tomcat/Jetty 低)、③ 非阻塞(支持异步)、④ 轻量、⑤ 灵活(可只用 HTTP 核心做轻量服务)。为什么性能好内存低:基于 XNIO(非阻塞 IO 框架)+ 精简设计(benchmark 常优于 Tomcat/Jetty、内存更低)。对比 Tomcat:Undertow 性能更好内存更低、Tomcat 生态成熟久经验证。适用:高并发、资源受限(容器化/微服务)、追求极致性能低内存。注意 Undertow 较新生态不如 Tomcat。理解「Undertow 高性能低内存非阻塞:基于 XNIO(非阻塞 IO)性能好/内存低/精简;性能常优于 Tomcat 内存更低;适合高并发+资源受限(容器化);较新生态不如 Tomcat」,就掌握了 Undertow。
五、怎么选与切换
综合对比,给出选择和切换方法:
选择(按需求):
大多数场景 → Tomcat(默认、成熟、生态好)
→ 没特殊需求就用它(最稳妥)
高并发/低内存/极致性能 → Undertow
→ 资源受限、性能敏感(容器化、微服务)
轻量嵌入/灵活定制 → Jetty
→ 把 Web 服务嵌入产品、需要模块化裁剪
关键判断:
① 容器往往不是瓶颈(瓶颈在数据库、业务、网络)
→ 大多数应用换容器性能提升有限,别盲目换
② 除非确实高并发/资源受限,用默认 Tomcat 就好
③ 真要换(Undertow/Jetty),先压测验证收益
在 Spring Boot 里切换(成本极低):
① 排除默认的 spring-boot-starter-tomcat
② 引入 spring-boot-starter-undertow(或 jetty)
→ 代码不用改(都实现 Servlet 规范、Spring Boot 抽象了)
切换的意义:
同一套代码,只改依赖,就能换容器
→ 可以先用 Tomcat、真遇到问题再换(低成本试)
核心总结:
三者都是 Servlet 容器(功能等价)
Tomcat 主流成熟(默认,大多数场景)
Undertow 高性能低内存(高并发/资源受限)
Jetty 轻量灵活(嵌入/定制)
切换只改依赖,别盲目换(容器很少是瓶颈)
选择(按需求):大多数场景用 Tomcat(默认成熟)、高并发/低内存/极致性能用 Undertow、轻量嵌入/灵活定制用 Jetty。关键判断:容器往往不是瓶颈(瓶颈在数据库/业务/网络)、除非确实高并发/资源受限用默认 Tomcat、真要换先压测验证。在 Spring Boot 切换(成本极低):排除 spring-boot-starter-tomcat、引入 spring-boot-starter-undertow(或 jetty),代码不用改。理解「选择:大多数用 Tomcat(默认)、高并发低内存用 Undertow、轻量嵌入用 Jetty;判断:容器很少是瓶颈别盲目换、真要换先压测;Spring Boot 切换只改依赖代码不动」,就掌握了选择和切换。
记忆钩子:「Tomcat/Jetty/Undertow 都是 Servlet 容器(都实现 Servlet 规范/跑 Java Web 应用/Spring Boot 内嵌容器,功能等价);①Tomcat(Apache,主流成熟,Spring Boot 默认,生态最全文档社区最好最稳定,功能全面稍重,大多数场景首选)②Jetty(Eclipse,轻量灵活模块化,易嵌入定制,被很多产品内嵌如 Hadoop,适合轻量嵌入/灵活定制)③Undertow(Red Hat/JBoss,高性能低内存非阻塞,基于 XNIO,适合高并发/资源受限/容器化,较新生态不如 Tomcat);★选择:大多数用 Tomcat(容器很少是瓶颈别盲目换)、高并发低内存用 Undertow、轻量嵌入用 Jetty;Spring Boot 切换只改依赖(排除 starter-tomcat 引入 starter-undertow/jetty)代码不动」。
七、常见误区与追问
- 误区:Undertow 性能好就应该都换成 Undertow。 不必——对大多数业务应用,容器往往不是性能瓶颈(瓶颈通常在数据库、业务逻辑、网络),换容器带来的性能提升可能微乎其微,却损失了 Tomcat 的成熟生态;除非确实是高并发、资源受限、对内存/性能有极致要求,否则用默认的 Tomcat 就好;真要换先压测验证收益。
- 误区:三个容器功能不一样、代码要改。 功能等价——三者都实现了 Servlet 规范,都能跑同样的 Java Web 应用;在 Spring Boot 里切换只改依赖(排除 Tomcat、引入 Undertow/Jetty),代码不用改(Spring Boot 抽象了容器);只是实现、性能、生态、定位不同。
- 误区:Spring Boot 默认用 Tomcat 是随便选的。 不是——Tomcat 生态最成熟(文档最全、社区最大、被验证最多、最稳定),遇到问题最容易解决,功能全面、久经考验,是最稳妥的默认选择;对大多数场景够用(容器很少是瓶颈);所以 Spring Boot 默认给最稳妥的 Tomcat。
- 误区:Jetty 已经过时了。 Jetty 没过时——它历史悠久、轻量灵活、模块化好,被很多产品内嵌作为 HTTP 服务(Hadoop、各种中间件),在「轻量嵌入、灵活定制」场景仍是好选择;只是在 Spring Boot 应用里,Tomcat(默认)和 Undertow(高性能)更常被讨论。
- 追问:Tomcat、Jetty、Undertow 有什么区别,怎么选? 三者都是 Servlet 容器(都实现 Servlet 规范、能跑 Java Web 应用),区别在定位和特性:Tomcat(Apache)最主流、生态最成熟、最稳定,是 Spring Boot 默认;Jetty(Eclipse)轻量、灵活、模块化,适合嵌入式和定制;Undertow(Red Hat)高性能、低内存、非阻塞(基于 XNIO),适合高并发和资源受限;选择:大多数场景用 Tomcat(默认、成熟、生态好),高并发/低内存/极致性能用 Undertow,轻量嵌入/灵活定制用 Jetty;因为容器往往不是瓶颈,别盲目换。
- 追问:在 Spring Boot 里怎么把 Tomcat 换成 Undertow? 在 spring-boot-starter-web 里排除 spring-boot-starter-tomcat(用 exclusion),然后引入 spring-boot-starter-undertow 依赖;代码完全不用改(因为都实现 Servlet 规范、Spring Boot 抽象了内嵌容器);换成 Jetty 同理(排除 tomcat、引入 spring-boot-starter-jetty);切换成本极低,可以先用 Tomcat、真遇到性能问题再换并压测验证。
- 追问:什么情况下应该考虑用 Undertow 替代 Tomcat? 高并发场景(性能敏感、请求量大)、资源受限场景(内存少,如容器化部署、微服务,Undertow 内存占用更低)、对性能/内存有极致要求时;Undertow 基于 XNIO 非阻塞 IO、精简设计,性能和内存表现常优于 Tomcat;但要注意 Undertow 较新、生态不如 Tomcat 成熟(遇到问题资料相对少);换之前最好压测验证在你的场景下确实有明显收益。
八、加强记忆
Tomcat、Jetty、Undertow 都是「Servlet 容器(Web 服务器)」——都实现了 Servlet 规范、能跑 Java Web 应用,是 Spring Boot 支持的三种内嵌容器(功能等价)。① Tomcat(Apache,最主流)——生态最成熟(文档最全、社区最大、最稳定、被验证最多),功能全面(稍重),是 Spring Boot 默认;② Jetty(Eclipse)——轻量、灵活、模块化,历史悠久、被很多产品内嵌(Hadoop 等),适合轻量嵌入和灵活定制;③ Undertow(Red Hat/JBoss)——高性能、低内存、非阻塞(基于 XNIO),适合高并发和资源受限(容器化/微服务),但较新、生态不如 Tomcat。怎么选:大多数场景用 Tomcat(默认、成熟、生态好,容器往往不是瓶颈、别盲目换);高并发/低内存/极致性能用 Undertow;轻量嵌入/灵活定制用 Jetty。在 Spring Boot 里切换成本极低:排除 spring-boot-starter-tomcat、引入 spring-boot-starter-undertow(或 jetty),代码不用改(都实现 Servlet 规范、Spring Boot 抽象了容器)——可以先用 Tomcat、真遇到问题再换(并压测验证)。一句话「三者都是 Servlet 容器(功能等价):Tomcat 主流成熟(默认,生态最好,大多数场景)、Jetty 轻量灵活(嵌入/定制)、Undertow 高性能低内存(高并发/资源受限,基于 XNIO);选择大多数用 Tomcat(容器很少是瓶颈别盲目换)、高并发用 Undertow、嵌入用 Jetty;Spring Boot 切换只改依赖代码不动」。