SpringMVC与Servlet容器[Tomcat]

SpringMVC与Servlet容器[Tomcat]

  • [1. Servlet容器:Java Web应用的运行基石](#1. Servlet容器:Java Web应用的运行基石)
    • [1.1 容器的本质与核心职责](#1.1 容器的本质与核心职责)
    • [1.2 从传统部署到嵌入式演进](#1.2 从传统部署到嵌入式演进)
  • [2. Tomcat与Undertow对比](#2. Tomcat与Undertow对比)
    • [2.1 设计哲学与特性](#2.1 设计哲学与特性)
    • [2.2 性能差异的根源:线程模型 vs 事件驱动](#2.2 性能差异的根源:线程模型 vs 事件驱动)
    • [2.3 选型建议:没有最好,只有最合适](#2.3 选型建议:没有最好,只有最合适)
  • [3. HTTP与WebSocket:协作而非替代](#3. HTTP与WebSocket:协作而非替代)
    • [3.1 核心差异:通信模式的不同](#3.1 核心差异:通信模式的不同)
    • [3.2 清晰界定:两种协议的角色与协同](#3.2 清晰界定:两种协议的角色与协同)
  • [4. 总结](#4. 总结)
  • [5. Tomcat与Spring Boot](#5. Tomcat与Spring Boot)
    • [5.1 Tomcat与Spring Boot的分工🏗️](#5.1 Tomcat与Spring Boot的分工🏗️)
    • [5.2 Tomcat的核心作用:连接器、线程池与容器🧵](#5.2 Tomcat的核心作用:连接器、线程池与容器🧵)
    • [5.3 Tomcat的容量:线程、连接与队列📊](#5.3 Tomcat的容量:线程、连接与队列📊)
    • [5.4 总结](#5.4 总结)

姊妹篇Idea2023创建Servlet项目


在构建【Java Web应用】时,无论我们使用的是 传统的Spring MVC 还是 现代化的Spring Boot(依赖 spring-boot-starter-web),一个核心组件总是在幕后默默工作 ------ 【Servlet容器】 。它就像是数字世界中的 "引力",虽然不经常被直接讨论,++却决定了 应用 如何 与 网络世界连接、通信及扩展++ 。常见的Servlet容器有:Tomcat、Undertow、Jetty、Weblogic 等 。同时,为满足实时交互的需求,WebSocket协议也已成为现代应用的标配。


1. Servlet容器:Java Web应用的运行基石

1.1 容器的本质与核心职责

"容器"一词非常形象。我们可以把它理解为 专门为"Servlet"这类程序提供生存、运行和管理环境的托管平台Servlet 本身是一个标准的【Java接口】javax.servlet.Servlet,jakarta.servlet.Servlet(Java EE已经正式更名为Jakarta EE[雅加达])):定义了处理网络请求和响应的生命周期方法

Servlet容器的核心职责包括以下4个方面

  • 生命周期管理负责Servlet类文件的加载、实例化、初始化(调用init())、服务调用(调用service())以及最终的销毁(调用destroy()
  • 通信协议抽象 :容器接管了复杂的网络I/O操作。++它将原始的、基于TCP/IP的HTTP字节流,解析并封装成Java开发者友好的 HttpServletRequestHttpServletResponse 对象++。开发者无需处理套接字编程,只需专注于业务逻辑。
  • 资源与环境管理 :提供统一的 ServletContext 环境来存放共享数据,管理用户会话(HttpSession),并处理线程池、连接池等基础资源。
  • 规范与可移植性保障:所有遵循 Java Servlet规范的容器(如Tomcat, Undertow, Jetty, WebLogic等),其行为都是一致的。这确保了基于Servlet开发的应用可以 "一次编写,到处运行",在不同容器间迁移时,核心代码无需修改。



1.2 从传统部署到嵌入式演进

Servlet容器的角色演进

  • 传统部署模式(十几年前) :Tomcat 作为一个独立的、系统级的服务器进程存在(需要先独立安装、配置Tomcat)。开发者需要将应用程序打包成 .war 文件,然后将其部署到 Tomcat 的指定目录(如webapps)。应用作为容器的 "租客" 运行。
  • 现代嵌入式模式(Spring Boot时代) :Spring Boot 通过 spring-boot-starter-web 等组件,将Tomcat 或 Undertow 作为 内嵌的库(JAR包) 直接打包进应用。当执行 java -jar 或者 YourApplication.main() 启动应用时,Tomcat容器 从应用内部启动,成为 jvm进程 的一部分。这种方式简化了部署,实现了应用的自包含,完美契合了微服务和云原生理念。

2. Tomcat与Undertow对比

虽然都符合Servlet规范,但 Apache Tomcat 和 Red Hat的Undertow 在 架构设计 和 性能特性上有着显著差异,这直接影响了它们在不同场景下的适用性。

2.1 设计哲学与特性

对比维度 Apache Tomcat Undertow (Red Hat)
出身与定位 Apache基金会旗舰项目,历史最悠久、生态最成熟、事实上的行业标准。定位为通用、稳健的Web应用服务器。 源于JBoss/WildFly应用服务器,以高性能、低开销、可嵌入为核心设计目标 的现代化Web服务器。
架构与I/O模型 早期基于 阻塞式I/O(BIO) ,后引入 非阻塞I/O(NIO/NIO2) 选项。采用较为传统的连接器(Connector)架构。 从头至尾采用非阻塞I/O ,基于高性能的XNIO框架。采用 事件驱动、回调式的架构,核心JAR包仅约1MB,极其轻量。
性能特点 均衡稳健。在常规的请求-响应式Web应用(如MVC、REST API)中表现可靠。在高并发长连接场景下,默认的线程池模型可能带来更高的内存开销和上下文切换成本。 高并发、低延迟、低内存占用 。其事件驱动模型在处理 大量并发持久连接(如WebSocket、HTTP Streaming)和文件传输时优势明显,资源利用率极高。
内存与启动速度 相对较高(核心模块约8MB),启动速度适中。 极致轻量(核心模块约1MB),启动速度通常更快,非常适合资源受限的微服务和Serverless环境。
功能与扩展 功能全面,内置JSP编译器、WebSocket、安全管理等大量企业级特性,生态系统庞大。 "核心精简,按需扩展"。专注于Servlet和WebSocket核心,其他功能需通过插件或编程方式添加,提供了极高的灵活性。

2.2 性能差异的根源:线程模型 vs 事件驱动

两者性能差异的本质源于其处理请求的模型不同。我们可以通过一个 "餐厅后厨" 的类比来理解:

  • Tomcat 的线程池模型 :好比一个拥有固定厨师团队(工作线程)的餐厅。每个顾客订单(HTTP请求)需要由一位厨师 全程负责,从接单到上菜。如果某道菜制作很慢(如慢SQL查询),对应的厨师就会被一直占用,即使他大部分时间在等待。当厨师全部被占用时,新顾客只能排队等候(请求队列)。这种模型简单可靠,但在面对大量 "慢订单" 或 需要长时间保持连接的"包间服务"(WebSocket)时,资源效率会下降。

  • Undertow 的事件驱动模型 :如同一个高度协同的现代化厨房。厨师被细分为 接单员、配菜员、炒菜员、摆盘员 (相当于多个事件处理器)。一个订单被拆解成多个步骤,每个步骤由最合适的专员快速处理,然后立即转交下一步,专员不会被单个订单长期阻塞。这种模式特别擅长处理 海量并发的小任务或需要长时间维持但交互稀疏的连接,资源复用率极高。


2.3 选型建议:没有最好,只有最合适

  • 选择 Tomcat,如果 :项目是典型的Web应用(如企业内部管理系统、电商前台),追求 极致的稳定性、广泛的社区支持和丰富的现成文档;或者项目团队对其有深厚的技术积累。Tomcat 依然是 Spring Boot的默认选择,这本身就证明了其普适性。
  • 选择 Undertow,如果 :应用是 高并发的API网关、实时通信服务(如聊天、游戏) ,或运行在资源严格受限的 微服务/Serverless环境 中;对 极致的吞吐量和低延迟有明确要求,并愿意为了性能进行更精细的配置。

3. HTTP与WebSocket:协作而非替代

在理解容器之后,我们还需要看清在其上运行的协议。WebSocket 常被误解为 HTTP 的替代品,实则不然,它们是互补的协作关系。


3.1 核心差异:通信模式的不同

  • HTTP协议:

    • HTTP协议是Web的基石,但其 【请求-响应(Request-Response) 模型】存在天然限制:通信永远由客户端发起,服务器无法主动推送信息。这对于需要实时性的应用(如股票行情、在线协作)是致命缺陷。
  • WebSocket协议:

    • WebSocket协议 的出现 正好填补了这一空白。它在一次HTTP "握手" 升级后,建立一条 全双工、持久化的TCP通道。此后,服务器和客户端可以随时、主动地向对方发送消息,实现了真正的双向平等通信。

3.2 清晰界定:两种协议的角色与协同

下图清晰地展示了一次典型的 WebSocket连接建立过程,以及两种协议如何协同工作
服务器 (Servlet容器) 客户端 (浏览器) 服务器 (Servlet容器) 客户端 (浏览器) 第一阶段: HTTP握手升级 第二阶段: WebSocket全双工通信 loop [持续双向通信] HTTP GET请求 含头: Upgrade: websocket HTTP 101 Switching Protocols 同意升级协议 (服务器可主动推送) "您有新的消息" (客户端随时发送) "用户回复:你好!" 推送数据... 发送数据...

从图中可以看出,HTTP与WebSocket是前后衔接、各司其职的:

  1. 连接建立 :WebSocket连接始于一个特殊的 HTTP请求 (使用Upgrade: websocket头部)。服务器响应101状态码,表示协议 "升级" 成功。
  2. 持久通信 :握手完成后,连接即切换至 WebSocket协议。此后,双方在 同一TCP连接上 进行轻量级的帧通信,头部开销极小,效率远高于频繁建立HTTP连接。
  3. 协作共存 :在现代应用中,一个页面通常会同时使用两种协议:用 HTTP 加载静态资源、调用REST API提交数据;用 WebSocket 维持一个实时通道,接收服务器推送的通知、聊天消息或实时数据更新。

因此,Tomcat 和 Undertow 作为现代 Servlet容器,都 同时支持HTTP和WebSocket协议,成为支撑这种混合通信模式的基础平台。


4. 总结

通过以上分析,我们可以清晰地看到一条技术演进的脉络:

  1. Servlet容器 作为标准化平台,是Java Web应用不可动摇的根基,++它让开发者从【底层网络细节】中解放出来++
  2. Tomcat 与 Undertow 代表了这一根基下的两种不同发展路径:① Tomcat沿着"功能全面、稳定优先"的道路成为行业支柱;② Undertow则沿着"极致性能、轻量灵活"的道路,迎合了云原生时代对效率和资源密度的新需求。技术选型应基于实际业务场景,而非盲目追求性能指标
  3. HTTP 与 WebSocket 的共存,体现了Web协议为解决不同问题而进行的自然扩展与协作。从单向请求到双向实时通信,协议的发展持续赋能更丰富的Web体验。

5. Tomcat与Spring Boot

5.1 Tomcat与Spring Boot的分工🏗️

我们可以把整个 Java Web应用 看成一栋提供服务的 "大楼":

  • Tomcat :是这栋楼的 前台、门卫和后勤调度中心。它负责与外界(网络)打交道,处理所有接入、派发和基础的维护工作。
  • Spring Boot (Spring MVC) :是楼里各个专业的 业务部门(如销售部、客服部)。它们专注于处理具体的业务逻辑。

当一个HTTP请求到来时,流程是这样的

  • 网络请求 → Tomcat(监听端口、解析协议、分配线程) → Spring MVC的 DispatcherServlet(中央路由器) → @Controller(具体处理者) → 原路返回响应。

org.springframework.web.servlet.DispatcherServlet


5.2 Tomcat的核心作用:连接器、线程池与容器🧵

Tomcat在这里面主要干了三件至关重要的事:

  1. 网络连接与协议解析(连接器 - Connector)

    • 作用 :它在一个端口(如默认的8080)上 "竖起耳朵" 监听。当浏览器发来一个原始的、基于TCP/IP的HTTP请求数据流时,Tomcat 负责读取这个数据流,并按照 HTTP协议规范,将其解析成 Java代码可以方便操作的 HttpServletRequestHttpServletResponse 对象。这是所有 Web交互的基础
  2. 请求调度与线程管理(线程池 - Thread Pool)

    • Tomcat 内部维护了一个或多个 线程池 (通常是 java.util.concurrent.ThreadPoolExecutor 的变体)。
    • Tomcat 在启动时就创建好了一组线程(称为工作线程)。这些线程一直在等待任务。
    • 当一个新的HTTP请求被连接器接收后,Tomcat会从它的 ++线程池中取出一个空闲的 工作线程++ ,将这个请求(及上面提到的 Request/Response 对象)【分配】给它 。然后,这个 Tomcat 的工作线程 【全程负责】 调用后续的 Spring MVC流程(包括Controller方法),直到返回响应。处理完毕后,该线程被释放回线程池,等待下一个请求 。所以,++处理请求的线程是 Tomcat 的,不是 Spring 或 Controller 创建的++
  3. 生命周期与组件管理(容器 - Container)

    • Tomcat 管理着 Servlet(如Spring MVC的核心 【DispatcherServlet】)、Filter 等组件的加载、初始化和销毁。在 Spring Boot 中,虽然我们通过内嵌方式启动,但 Tomcat 依然履行着这个职责。

5.3 Tomcat的容量:线程、连接与队列📊

Tomcat处理请求的能力受几个关键配置参数控制,它们共同作用,形成了一个处理管道:

复制代码
graph LR
    subgraph A [Tomcat 请求处理管道]
        direction LR
        Client[客户端请求] --> Connector[连接器<br>Acceptor线程接收];
        Connector --> B{有空闲工作线程?};
        B -- 是 --> WorkerThread[工作线程处理<br>(执行Controller方法)];
        B -- 否 --> Queue[等待队列<br>(容量: acceptCount)];
        Queue --> C{队列未满?};
        C -- 是 --> Wait[请求在队列等待];
        C -- 否 --> Reject[立即拒绝连接];
        Wait --> D[有空闲线程时出队处理];
        WorkerThread --> Response[返回响应];
    end

1. 处理线程数 (maxThreads)

  • 含义 :Tomcat工作线程池的 最大线程数 。这直接决定了 应用同时能处理多少个请求
  • 默认值:通常是200(不同版本和配置有差异)。
  • 影响 :如果应用所有Controller方法都很快,那么200个线程足以支撑很高的并发(因为线程复用)。但如果某个请求处理很慢(比如查询耗时2秒),那么在这2秒内,这个线程就被占用着。当200个线程全部被慢请求占用时,第201个请求就必须等待,即使CPU还很空闲。

2. 等待队列 (acceptCount)

  • 含义 :当所有工作线程都在忙时,新来的请求不会立即被拒绝,而是进入一个 等待队列。这个参数就是队列的长度。
  • 默认值:通常是100。
  • 影响 :结合上面的例子,当200个线程都忙时,接下来的100个请求可以在队列中排队等待。队列也满后,第301个及以后的请求就会被 Tomcat 立即拒绝,返回连接失败的错误。

3. 最大连接数 (maxConnections)

  • 含义 :Tomcat在任一时刻能够接收和管理的最大 网络连接数(包括正在处理的请求和保持活跃但空闲的连接)。
  • 默认值 :对于NIO模式(默认),通常是 10000
  • 与线程数的区别 :一个连接(如Keep-Alive连接)可以被多个顺序发生的请求复用。maxConnections 限制的是TCP连接层面的数量,通常远大于 maxThreads

5.4 总结

Tomcat 与 Spring Boot 的核心分工如下:

组件 核心职责 类比
Tomcat HTTP服务器 + Servlet容器 : 1. 网络监听、协议解析。 2. 管理线程池,为每个请求分配工作线程 。 3. 管理请求队列,控制流量洪峰。 4. 加载和管理Servlet生命周期。 公司的前台、行政和IT基础部门:负责接电话、分配工位、提供电脑、保证办公室能运转。
Spring Boot (Spring MVC) Web框架 + 业务容器 : 1. 提供 DispatcherServlet(总路由器) 。 2. 将请求路由到对应的 @Controller/@RequestMapping 。 3. 处理参数绑定、数据验证、视图渲染等。 4. 管理业务Bean、事务、安全等。 公司的各个业务部门:如销售部(OrderController)、用户部(UserController),他们使用公司提供的基础设施来专注处理专业业务。

理解了这个分工,也就能明白为什么我们常说 "Spring Boot应用" 而不是 "Tomcat应用" ------ 因为Tomcat 已经变成了这个应用内部的一个 【标准化的、负责底层通信的组件】,而业务逻辑完全由Spring 框架掌控


笑一个吧,加油啊!努力生活!!!

相关推荐
xiaolyuh1239 小时前
【XXL-JOB】执行器 Netty服务 & Tomcat 进程+资源共用详解
java·tomcat
BD_Marathon9 小时前
启动tomcat报错,80 端口已经被其他程序占用
java·tomcat
计算机毕设指导69 小时前
基于微信小程序的精致护肤购物系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·intellij-idea
进阶的小名9 小时前
[超轻量级消息队列(MQ)] Redis 不只是缓存:我用 Redis Stream 实现了一个 MQ(自定义注解方式)
数据库·spring boot·redis·缓存·消息队列·个人开发
何中应9 小时前
@Autowrited和@Resource注解的区别及使用场景
java·开发语言·spring boot·后端·spring
Chan1620 小时前
【 Java八股文面试 | JavaSE篇 】
java·jvm·spring boot·面试·java-ee·八股
FG.21 小时前
LangChain4j
java·spring boot·langchain4j
smileNicky1 天前
SpringBoot系列之集成Pulsar教程
java·spring boot·后端
麦麦大数据1 天前
J009 美食推荐可视化大数据系统vue+springboot
vue.js·spring boot·mysql·推荐算法·美食·可视化分析·沙箱支付