Spring Boot内嵌容器:小花ai助手整理Tomcat与Undertow选型指南

小编 2 0

发布时间:2026年4月10日
目标读者:技术入门/进阶学习者、在校学生、面试备考者、相关技术栈开发工程师
文章定位:技术科普 + 原理讲解 + 代码示例 + 面试要点

一、开篇引入:为什么每个Spring Boot开发者都要搞懂内嵌容器?

在Spring Boot出现之前,用Java开发Web应用,得先把代码打成WAR包,然后手动部署到外部的Tomcat或Jetty容器中,还得配置一堆xml文件。这不仅步骤繁琐,还容易出错——环境不一致、配置遗漏、启动失败,每个问题都够让人折腾半天。

「Spring Boot的嵌入式Web容器」 (Embedded Web Container),正是为解决上述痛点而生。它将Web服务器直接打包到应用程序中,让应用通过java -jar就能独立运行,无需任何外部容器。内嵌容器(Tomcat、Jetty、Undertow、Netty)是Spring Boot最核心的基础能力之一,也是面试中绕不开的高频考点。很多初学者只知道“能用”,一旦问到“Spring Boot怎么启动Tomcat”“Tomcat和Undertow有什么区别”“为什么Spring Boot 4移除了Undertow”就卡住了。

本文将从小花ai助手整理的资料出发,从痛点切入,带你理清嵌入式容器的核心概念、底层原理、选型对比和面试要点,帮你建立从概念到实战的完整知识链路。

二、痛点切入:为什么需要嵌入式容器?

2.1 传统方式的“四宗罪”

在嵌入式容器出现前,开发Web应用的标准流程是这样的:

xml
复制
下载
运行
<!-- web.xml 传统配置示例 -->
<web-app>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-servlet.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

这个过程存在以下痛点:

  • 环境耦合:开发环境装一个Tomcat,测试环境装一个Tomcat,生产环境还得单独部署一个容器。不同环境的版本差异往往导致“本地能跑,线上挂了”的窘境。

  • 配置繁琐:每个项目都需要配置web.xml、server.xml等配置文件,重复劳动。

  • 部署笨重:每次部署都需要停止容器、拷贝WAR包、重启容器,运维成本高。

  • 扩展性差:做微服务拆分时,每个服务都需要一个独立的容器实例,资源浪费严重。

2.2 嵌入式容器如何破局?

Spring Boot在spring-boot-starter-web中默认内置了Tomcat作为嵌入式容器,应用直接打成JAR包,运行java -jar即可启动一个完整的Web服务器-7。这种“把服务器装在应用里”的做法,彻底解决了传统方式的痛点:

  • 环境统一:容器版本和应用代码一起打包,不存在环境差异问题。

  • 零配置:无需web.xml,Spring Boot自动配置。

  • 一键部署:直接运行JAR包,无需额外操作。

  • 云原生友好:非常适合Docker容器化部署和微服务架构。

三、核心概念讲解:什么是嵌入式Web容器?

3.1 定义拆解

嵌入式Web容器(Embedded Web Container),顾名思义,就是把Web服务器(如Tomcat)作为应用程序的一部分,嵌入在应用中运行,而不是单独部署一个外部服务器。

拆解关键词:

  • “嵌入式” :指容器与应用运行在同一个进程中,不需要额外的进程或环境。

  • “Web容器” :指实现了Servlet规范的服务器,负责接收HTTP请求、调用Servlet处理、返回响应。

3.2 生活化类比

想象一下传统方式和嵌入式容器的区别:

  • 传统方式(外部容器) :像在商场里开一个档口,商场提供水电气等基础设施。但如果商场关门,档口就没办法营业了。这种模式依赖外部环境。

  • 嵌入式方式 :像开一辆移动餐车,餐车自带发电机、水源和厨房设备,随时可以开出去做生意。无论走到哪里,餐车自身就能独立运行。

3.3 作用和价值

嵌入式容器的核心价值在于 “让Java Web应用变成独立运行的可执行程序” 。开发者不再关心外部容器的安装和配置,只需专注于业务逻辑。这种设计为微服务架构、容器化部署提供了天然支持,使Java应用能够像Node.js应用一样轻量快捷地运行。

四、关联概念讲解:四大嵌入式容器对比

Spring Boot提供了四种嵌入式Web容器,可分为Servlet容器和Reactive容器两类-6

4.1 Tomcat(默认容器)

标准定义:Tomcat是Apache软件基金会的开源Servlet容器,实现了Servlet、JSP等Java Web技术规范,是Java Web开发中最常用的容器之一-30

特点

  • 生态最成熟,文档和社区支持最完善

  • 默认200个工作线程,适合大多数业务场景-50

  • 功能全面,稳定性高

4.2 Jetty

标准定义:Jetty是Eclipse基金会开发的轻量级Servlet容器,以快速启动和低内存占用著称-30

特点

  • 内存占用约50-80MB,比Tomcat轻量-37

  • 启动速度比Tomcat快约30%

  • 对长连接(WebSocket/SSE)支持更好

4.3 Undertow

标准定义:Undertow是Red Hat公司开发的高性能Servlet容器,基于NIO(非阻塞I/O)技术,具有低延迟和高吞吐量的特点-30

特点

  • 吞吐量比Tomcat高50%以上-37

  • 内存占用最低,约30-50MB

  • 支持HTTP/2和WebSocket

4.4 Netty

标准定义:Netty是一个高性能的网络框架,在Spring Boot中作为Reactive Web应用的底层容器(通过spring-boot-starter-webflux启用)-6

特点

  • 异步非阻塞模型

  • 适合Reactive编程(Spring WebFlux)

  • 不直接用于传统Servlet应用

五、概念关系与区别总结

四种容器的核心关系:

容器适用场景核心优势内存占用推荐指数
Tomcat传统企业应用生态完善、稳定可靠约100MB+⭐⭐⭐⭐⭐
Jetty轻量级/嵌入式设备启动快、长连接好约50-80MB⭐⭐⭐⭐
Undertow高并发API服务吞吐量高、内存低约30-50MB⭐⭐⭐⭐
NettyReactive/WebFlux异步非阻塞极低⭐⭐⭐

一句话概括:Tomcat是“稳定可靠的大本营”,Jetty是“灵活轻便的随身工具”,Undertow是“性能狂魔的加速器”,Netty则是“响应式编程的新赛道”。

六、代码/流程示例:容器配置与切换实战

6.1 默认配置(Tomcat)

Spring Boot默认使用Tomcat,零配置即可启动:

java
复制
下载
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

application.properties中配置容器参数:

properties
复制
下载
 端口配置
server.port=8080
server.servlet.context-path=/api

 Tomcat专属配置
server.tomcat.max-threads=200
server.tomcat.connection-timeout=30000

6.2 切换容器:从Tomcat到Jetty

pom.xml中排除Tomcat,引入Jetty-7-30

xml
复制
下载
运行
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <!-- 排除默认的Tomcat依赖 -->
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- 引入Jetty作为替代容器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
</dependencies>

6.3 切换容器:从Tomcat到Undertow

同样的方式,引入Undertow-7

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-undertow</artifactId>
</dependency>

6.4 自定义容器配置

实现WebServerFactoryCustomizer接口进行精细化配置-5

java
复制
下载
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

@Component
public class MyCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        factory.setPort(9090);           // 设置端口
        factory.setContextPath("/myapp"); // 设置上下文路径
        factory.setSessionTimeout(30);    // 设置会话超时(分钟)
    }
}

6.5 容器启动原理图

text
复制
下载
SpringApplication.run()


创建 ServletWebServerApplicationContext (特殊的IoC容器)


执行 onRefresh() 方法


createWebServer() —— 调用 ServletWebServerFactory

    ├── TomcatServletWebServerFactory
    ├── JettyServletWebServerFactory
    └── UndertowServletWebServerFactory


容器启动完成,应用开始监听端口

七、底层原理/技术支撑点

7.1 核心依赖:ServletWebServerApplicationContext

Spring Boot内嵌容器的底层依赖一个特殊的IoC容器——ServletWebServerApplicationContext。这个容器在启动过程中会主动寻找ServletWebServerFactory(Servlet Web服务器工厂),调用它来创建和启动嵌入式Web服务器-5

7.2 自动配置机制

ServletWebServerFactoryAutoConfiguration是关键的自动配置类。它会根据项目中实际引入的Web服务器包动态判断该创建哪个工厂实例:默认情况下引入spring-boot-starter-web后,会自动配置TomcatServletWebServerFactory-5

7.3 反射与类加载

Spring Boot利用类加载机制扫描META-INF/spring.factories文件中的自动配置类,并通过反射动态实例化相应的容器工厂。例如,检测到类路径存在org.eclipse.jetty.server.Server时,才会激活Jetty的自动配置。

为什么要在文章中提及这些底层知识点?

本文以理解概念、掌握用法、应对面试为主。底层原理的完整源码分析(如onRefresh()如何调用createWebServer()Tomcat.start()的具体实现)属于进阶内容,后续文章会单独深入讲解。了解上述定位,能让你对整个技术栈的脉络更清晰。

八、高频面试题与参考答案

8.1 Spring Boot支持哪些嵌入式Web容器?各自适用什么场景?

参考答案:Spring Boot支持Tomcat(默认)、Jetty、Undertow和Netty四种嵌入式Web容器-50踩分点:能说出四种容器名称并简单区分。

  • Tomcat:生态最完善,适合大多数传统Web应用和Spring Boot项目,默认选项。

  • Jetty:轻量级,启动快、内存小,对WebSocket长连接支持更好,适合嵌入式场景。

  • Undertow:高性能、低内存、高吞吐量,基于NIO,适合高并发API服务和微服务场景。

  • Netty:异步非阻塞,适用于Spring WebFlux响应式编程。

8.2 Spring Boot内嵌容器的启动流程是怎样的?

参考答案:Spring Boot在启动时,通过SpringApplication.run()方法创建ServletWebServerApplicationContext,然后执行onRefresh()方法调用createWebServer()createWebServer()会根据类路径中的依赖选择合适的ServletWebServerFactory(如TomcatServletWebServerFactory),创建并启动嵌入式服务器-5踩分点:能讲出“工厂模式”+“自动配置”两个关键词。

8.3 如何在Spring Boot中从Tomcat切换到Undertow?

参考答案:在pom.xml中,将spring-boot-starter-web依赖下的spring-boot-starter-tomcat排除,然后添加spring-boot-starter-undertow依赖即可-60踩分点:明确说出“排除Tomcat依赖→添加Undertow依赖”的步骤顺序。

xml
复制
下载
运行
<!-- 排除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>

8.4 Tomcat、Jetty、Undertow三者性能上有什么区别?

参考答案:在吞吐量方面,Undertow性能最优,比Tomcat高50%以上,在高并发场景下表现最为突出;Tomcat作为默认容器,性能均衡稳定,社区成熟度最高;Jetty启动速度最快,内存占用约50-80MB,适合资源受限的嵌入式场景和长连接服务-37踩分点:能从“吞吐量/启动速度/内存占用”三个维度展开对比。

8.5 如何自定义嵌入式容器的配置(如端口、线程数)?

参考答案:有两种方式:一是直接在application.propertiesapplication.yml中配置,如server.port=9090;二是实现WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>接口,在customize方法中设置端口、上下文路径等参数-5踩分点:明确说出两种方式的区别——配置文件适合简单配置,Customizer适合复杂定制。

九、结尾总结

9.1 核心知识回顾

本文围绕Spring Boot嵌入式Web容器这一核心能力,系统梳理了以下要点:

  1. 嵌入式容器的定义:把Web服务器嵌入到应用中,让Java应用独立运行。

  2. 四大容器对比:Tomcat(默认/生态成熟)、Jetty(轻量/长连接)、Undertow(高性能/低内存)、Netty(响应式)。

  3. 切换配置方法:排除Tomcat依赖,引入Jetty或Undertow依赖即可。

  4. 底层原理ServletWebServerApplicationContext + ServletWebServerFactory工厂模式 + 自动配置。

  5. 面试考点:容器类型、切换方法、性能差异、自定义配置。

9.2 重点提示与易错点

  • 端口冲突:默认8080端口易被占用,务必检查或修改-7

  • 依赖排除遗漏:切换容器时忘记排除spring-boot-starter-tomcat会导致多个容器共存,启动异常。

  • 容器配置优先级:代码中的WebServerFactoryCustomizer优先级高于application.properties

9.3 下一篇预告

下期将从源码层面深入剖析Spring Boot嵌入式容器的启动原理,带你一步步追踪onRefresh()createWebServer()Tomcat.start()的完整调用链路,从源码角度彻底搞懂内嵌容器的“黑魔法”。欢迎持续关注!

版权说明:本文基于小花ai助手整理的资料编写,旨在帮助开发者系统掌握Spring Boot嵌入式容器知识。如有疑问或建议,欢迎在评论区交流讨论。