Skip to content

Spring Boot 支持哪些嵌入 Web 容器? ​

  • 标签:Spring Boot、后端

🏛 业务架构师 ​

Spring Boot 支持三种内嵌容器:

  • Tomcat(默认):最成熟、生态最广,历史包袱也最多;
  • Jetty:轻量、启动快,长连接场景(WebSocket 老项目)有积累;
  • Undertow:高并发下内存占用和性能表现优秀。

切换方式是排除默认再引入对应 starter(spring-boot-starter-jetty/undertow)。

业务架构师视角,我的选型逻辑是**"默认不动,理由充分才换"**:

  1. 绝大多数业务系统:保留 Tomcat。它的稳定性记录、社区资料量、与监控/诊断工具的兼容都最优,团队熟悉度本身就是运维资产。没有量化瓶颈就换容器,属于无收益的差异化;
  2. 换的真实场景:内存极度敏感(大量小 Pod 部署,Undertow 省下的堆是真实成本);连接数异常高的推送类服务;或公司统一技术栈决策;
  3. 比选容器更值得投入的是容器参数治理:server.tomcat.threads.max(默认 200)、max-connections(默认 8192)、accept-count——这些参数与业务峰值 QPS、依赖 RT 的匹配度,直接决定大促时的表现。我见过太多团队纠结容器选型,却让默认 200 工作线程扛着秒杀流量。

另外注意 JDK 21+ 虚拟线程(spring.threads.virtual.enabled=true)大幅改变了线程模型——2026 年这个开关的收益可能远大于换容器。

🏗 系统架构师 ​

可选清单:Tomcat(默认)、Jetty、Undertow(Servlet 栈);Netty(WebFlux/Reactive 栈,Spring Cloud Gateway 基于它)。切换即换依赖:排除 web starter 的 tomcat,引入 jetty/undertow 对应 starter。

选型逻辑(我的对比):

  • Tomcat:默认、生态最全、排障资料最多——没有特殊理由不换;
  • Undertow:内存占用低,少量线程支撑大量连接,适合高连接数与资源敏感部署;
  • Jetty:轻量,嵌入式与 WebSocket/长连接场景友好;
  • Netty:非 Servlet 场景(网关、推送、RPC 传输层)的事实标准。

运维参数才是重点:threads.max(默认 200)、max-connections(8191)、accept-count(100)要与下游容量联动推导,不是拍脑袋调大——容器线程打满的下一个受害者一定是数据库连接池。K8s 里还要配 graceful shutdown 与 preStop 摘流,保证滚动发布不丢在途请求。

💻 全栈开发专家 ​

Servlet 栈:Tomcat(默认)、Jetty、Undertow;Reactive 栈:Netty(默认) + Tomcat/Jetty/Undertow。

切换 Jetty 的标准操作:把 starter-web 里的 tomcat 排掉,再引 jetty:

xml
<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-jetty</artifactId>
</dependency>

选型经验:默认 Tomcat 生态最熟、资料最多;追求长连接和低内存选 Undertow;Jetty 多为老项目延续。调优三件套(默认值要背):

yaml
server:
  tomcat:
    threads:
      max: 200            # 工作线程
    max-connections: 8192
    accept-count: 100

K8s 实践必配两件事:优雅停机 server.shutdown: graceful + spring.lifecycle.timeout-per-shutdown-phase: 30s(配合 preStop sleep 让 LB 摘流量);探针分离用 Actuator 的 liveness/readiness,避免慢启动被误杀引发重启风暴。开虚拟线程后 threads.max 语义弱化,瓶颈转移到下游连接池。