这个问题在 Java 后端开发圈子里被问了无数遍,但答案从来不是“非黑即白”的。选哪个容器,取决于你的业务场景、团队技术栈偏好以及运维成本。
作为在国内云计算和微服务架构领域摸爬滚打多年的开发者,我直接给你拆解这三个选手的核心差异,并给出落地建议。
1. Tomcat:稳如老狗的行业标准
定位:Servlet 规范的事实标准实现。
现状:Spring Boot 默认内置的就是 Tomcat。
- 优点:
- 生态无敌:几乎任何 Java Web 相关的文档、教程、第三方库都优先兼容 Tomcat。遇到问题搜一下全是解决方案。
- 稳定性极高:经过二十多年的考验,Bug 极少,内存泄漏问题在最新版本中已得到很好控制。
- 社区庞大:如果你需要一些特殊的 Valve(阀门)或者自定义 Realm(安全域),Tomcat 的插件机制非常成熟。
- 缺点:
- 资源占用略高:相比 Jetty 和 Undertow,Tomcat 在处理海量并发连接时,线程模型和对象创建开销稍大。
- 启动速度中规中矩:对于大型应用,初始化 Context 的过程相对较慢。
适用场景:
90% 的传统企业级应用、单体应用、对稳定性要求高于极致性能的场景。如果你没有明确的性能瓶颈,闭眼选 Tomcat,因为它最不容易出错,招人最容易上手。
2. Jetty:轻量灵活的可嵌入王者
定位:高度可嵌入、异步支持好的 Servlet 容器。
现状:广泛用于 DevOps 工具(如 Jenkins)、物联网网关、以及需要动态加载/卸载模块的场景。
- 优点:
- 极致的可嵌入性:Jetty 的设计初衷就是作为一个库(Library)而不是一个独立进程。你可以轻松地将它嵌入到任何 Java 应用中,甚至不需要
web.xml。 - 异步处理能力强:基于 NIO 的实现较早且成熟,适合长连接、WebSocket 等场景。
- 热部署友好:类加载器设计灵活,支持运行时动态修改代码或替换模块,非常适合开发调试环境。
- 极致的可嵌入性:Jetty 的设计初衷就是作为一个库(Library)而不是一个独立进程。你可以轻松地将它嵌入到任何 Java 应用中,甚至不需要
- 缺点:
- 配置复杂度:虽然可嵌入性强,但在复杂的生产环境配置上,文档不如 Tomcat 直观。
- 市场份额萎缩:随着 Spring Boot 拥抱 Tomcat 和 Undertow,Jetty 在新项目中的存在感变弱了。
适用场景:
需要深度定制 Servlet 容器的场景、DevOps 平台内部组件、IoT 设备端服务、或者你需要在一个 Jar 包里同时运行多个不同版本的 Web 应用。
3. Undertow:红帽亲生的高性能新星
定位:由 Red Hat 主导开发,基于 Netty 构建的高性能非阻塞 Servlet 容器。
现状:Spring Boot 2.x 之后的重要备选方案,WildFly/JBoss EAP 的默认容器。
- 优点:
- 性能怪兽:在高并发、低延迟场景下,Undertow 的表现通常优于 Tomcat 和 Jetty。它的请求处理路径更短,对象分配更少。
- HTTP/2 原生支持:对 HTTP/2 的支持非常彻底且高效。
- 无阻塞 I/O:完全基于 Netty,擅长处理大量并发连接,CPU 利用率更优。
- 缺点:
- 同步阻塞 API 的限制:虽然底层是非阻塞的,但它提供的 Servlet API 仍然是同步阻塞的。这意味着如果你的业务逻辑里有大量同步阻塞操作(如调用慢速数据库),并不能完全发挥其优势,甚至可能因为线程池调度带来额外开销。
- 生态兼容性:虽然主流框架都支持,但一些老旧的第三方库可能对 Undertow 有特定依赖或兼容性问题。
- 调试难度:由于底层涉及 Netty 的多层封装,排查某些网络层面的问题时,堆栈跟踪比 Tomcat 更难读。
适用场景:
高并发网关、API 密集型服务、对响应时间极其敏感的微服务、已经使用 Spring Cloud Gateway 或 Zuul 等现代网关架构的项目。
核心对比总结表
| 特性 | Tomcat | Jetty | Undertow |
|---|---|---|---|
| 主要厂商 | Apache | Eclipse (原 Mortbay) | Red Hat |
| I/O 模型 | BIO/NIO 混合 | NIO | NIO (基于 Netty) |
| 并发能力 | 中等 | 良好 | 优秀 |
| 内存占用 | 较高 | 中等 | 较低 |
| 启动速度 | 一般 | 快 | 快 |
| 生态系统 | 最完善 | 较好 | 增长中 |
| 学习曲线 | 低 | 中 | 中高 |
我的实战建议(How to Choose)
-
首选原则:默认即正义
如果你使用的是 Spring Boot,不要主动切换。Spring Boot 默认集成的是 Tomcat,这是经过数百万开发者验证的最稳妥组合。除非你有明确的性能监控数据证明 Tomcat 成为了瓶颈,否则不要为了“听起来很厉害”而更换容器。 -
何时切换到 Undertow?
- 你的应用是纯 API 服务,没有复杂的 JSP/Servlet 页面渲染需求。
- 压测数据显示 CPU 在高并发下成为瓶颈,且 Tomcat 的线程池调整无效。
- 你正在构建一个高性能的网关或XX服务器。
- 注意:切换时需要确保所有使用的框架(如 Hibernate, Jackson 等)在 Undertow 环境下无异常。
-
何时考虑 Jetty?
- 你需要将 Web 容器嵌入到一个非标准的 Java 进程中。
- 你需要频繁的热部署和动态类加载(例如某些插件化架构)。
- 你维护的是一个较老的遗留系统,且该系统原本就基于 Jetty 构建。
-
关于云原生和 Kubernetes
在 K8s 环境中,容器的启动速度和资源隔离很重要。Undertow 和 Jetty 在这两方面略有优势,但 Tomcat 通过优化 JVM 参数和 GC 策略,也能达到很好的效果。关键不在于容器本身,而在于 JVM 调优、JFR(Java Flight Recorder)监控以及合理的线程池配置。
最后提醒
别陷入“容器选型焦虑”。在现代微服务架构中,Nginx/OpenResty + Java 应用 的组合才是常态。Java 容器负责业务逻辑,前面的反向XX负责静态资源、SSL 终止和初步的流量清洗。因此,Java 容器本身的极限性能提升,往往不如前端 CDN 或负载均衡层的优化带来的收益大。
结论:
- 求稳、求快上线、求易维护 -> Tomcat
- 求极致并发、API 服务、愿意折腾调优 -> Undertow
- 需嵌入、需热部署、特殊架构需求 -> Jetty
大多数情况下,Tomcat 是唯一正确的选择。
云技术博客