第一章:Tomcat架构概述


1.1 Tomcat的角色与定位:Web服务器 vs Servlet容器

Tomcat 是什么?它既是一种轻量级 Web 服务器,也是一种符合 Java EE 规范的 Servlet 容器。

  • Web服务器:类似 Nginx、Apache HTTP Server,处理静态资源请求(如 HTML、CSS、JS)。

  • Servlet容器:它能解析 Java Web 应用,执行 Servlet 逻辑,是 J2EE 架构中的核心组件。

Tomcat 专注于 Servlet/JSP 执行环境,是大多数 Java Web 项目的默认运行平台。你可以理解为:

🧠 “Nginx 负责搬运砖(静态内容),而 Tomcat 负责烧菜(动态内容)。”


1.2 核心功能:网络连接器(Connector)与Servlet容器(Container)

Tomcat 架构的设计核心是 分离连接(Connector)与处理(Container)

  • Connector 负责“接收请求”:它监听端口、解析协议(如 HTTP/AJP),把原始 Socket 请求转换成 Java 对象(如 ServletRequest)。

  • Container 负责“处理请求”:它解析 URL、找到对应的 Servlet、执行业务逻辑并返回响应。

两者通过 Service 组件进行绑定,形成完整的请求处理路径。


1.3 架构图描述(文字形式)

用文字描述 Tomcat 的核心架构图,帮助建立层级结构的直观印象:

┌────────────────────┐
│      Server        │  ← Tomcat 最顶层组件,负责整体生命周期
└────────┬───────────┘│┌─────▼─────┐│   Service │  ← 每个 Server 可包含多个 Service└─────┬─────┘│┌───────▼────────┐│   Connector    │ ← 监听端口,接收并转换 HTTP/AJP 请求└────────┬───────┘│┌───────▼────────────┐│     Engine         │ ← 请求处理的核心入口,属于 Container└──────┬─────────────┘│┌─────▼─────┐│   Host    │ ← 虚拟主机,用于支持多域名部署└─────┬─────┘│┌────▼─────┐│ Context  │ ← 每个 Web 应用一个 Context(对应一个 WAR 包)└────┬─────┘│┌───▼────┐│Wrapper │ ← 每个 Servlet 一个 Wrapper,最终执行点└────────┘

从上图可见,请求从最底层的 Connector 发起,最终由 Wrapper 调用 Servlet 实现类处理业务逻辑。这就是 Tomcat 的核心处理链路。

第二章:核心组件详解


2.1 Server组件:管理Tomcat实例的生命周期

Server 是 Tomcat 的顶级组件,代表整个 Tomcat 实例,它的职责是控制整个服务的生命周期。

  • 代表类org.apache.catalina.core.StandardServer

  • 主要职责

    • 统一管理所有 Service

    • 监听 SHUTDOWN 命令端口(默认8005),优雅关闭。

    • 触发 init(), start(), stop() 生命周期方法。

💡 类比理解:

Server 就像是一个酒店的总经理,下面每个 Service 是一个功能部门,比如前台、后厨、客房管理。

🔍 架构图描述(Server层):
┌────────────────────┐
│      Server        │
│ 监听8005关闭端口   │
│ 管理多个Service     │
└────────┬───────────┘↓[多个Service]

2.2 Service组件:整合Connector与Engine

Service 是连接请求(Connector)和业务处理(Engine)的桥梁。

  • 代表类org.apache.catalina.core.StandardService

  • 主要职责

    • 一个 Service 包含:

      • 一个 Engine(处理业务逻辑)

      • 一个或多个 Connector(接收外部请求)

    • 多个 Connector 可以绑定同一个 Engine,实现多协议共享逻辑处理。

💡 类比理解:

Service 就像酒店里的“接待部门”:门童(Connector)负责迎客,带到接待柜台(Engine)处理入住流程。

🔍 架构图描述(Service层):
┌──────────────────────────┐
│          Service         │
│ ┌─────────────────────┐ │
│ │       Engine         │ │ ← 业务处理核心
│ └─────────────────────┘ │
│  ┌────────────┐  ┌────────────┐
│  │ Connector1 │  │ Connector2 │ ← 多个端口或协议接入
│  └────────────┘  └────────────┘
└──────────────────────────┘

2.3 Connector组件:协议解析与请求转发

Connector 负责与客户端打交道,是 Tomcat 与外部世界的接口。

  • 代表类org.apache.coyote.http11.Http11NioProtocol

  • 职责

    • 监听指定端口(如 8080)。

    • 解析 HTTP 或 AJP 协议,转换为 Request/Response 对象。

    • 将请求传入对应的 Engine 继续处理。

🌐 支持的协议实现:
模式类名特点
BIOHttp11Protocol同步阻塞,低性能
NIOHttp11NioProtocol异步非阻塞,推荐
APRHttp11AprProtocol / AjpAprProtocol高性能,依赖本地库
NIO2Http11Nio2ProtocolNIO 的改进版
🧪 示例:配置 NIO Connector(在server.xml中)
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"connectionTimeout="20000"maxThreads="200" />

2.4 Container组件:Servlet容器的分层结构

Container 是 Tomcat 的核心处理器,负责执行 Servlet 逻辑。

它包含 4 层结构,层层包裹,类似俄罗斯套娃:

层级代表类作用
EngineStandardEngineService 中唯一的业务处理容器
HostStandardHost虚拟主机,支持多域名部署
ContextStandardContext一个 Web 应用对应一个 Context
WrapperStandardWrapper每个 Servlet 一个 Wrapper
💡 类比理解:

Container 像一栋办公楼:

  • Engine 是大楼

  • Host 是楼层(不同租户)

  • Context 是部门

  • Wrapper 是员工(Servlet)

🔍 架构图描述(Container层):
Engine└── Host (域名)└── Context (Web应用)└── Wrapper (Servlet)

✅ 本章小结

  • Server 管理整个 Tomcat 实例生命周期。

  • Service 是连接外部请求(Connector)与内部业务(Engine)的桥梁。

  • Connector 接收客户端请求并解析协议。

  • Container 是核心执行单元,包含 Engine → Host → Context → Wrapper 四级结构。

第三章:请求处理流程


3.1 请求到达 Connector 的流程(Socket → ServletRequest)

  1. 浏览器发送 HTTP 请求
    例如访问 http://localhost:8080/demo/hello,TCP 三次握手后,请求数据会到达 Tomcat 监听的端口(默认 8080)。

  2. Connector 接收请求

    • 对应类:org.apache.coyote.http11.Http11NioProtocol

    • 监听线程(Acceptor)接收连接请求,并交给 Poller 线程注册到 Selector(NIO 模型)。

  3. 协议解析

    • 使用 Http11Processor 解析 HTTP 协议。

    • 将解析结果封装成 org.apache.coyote.Requestorg.apache.coyote.Response 对象。

  4. 适配成 Servlet API

    • CoyoteAdapter 将底层 Request/Response 转换为 HttpServletRequestHttpServletResponse,进入容器处理流程。

🔍 流程图(文字版):
浏览器 → TCP连接 → Connector监听端口↓Acceptor线程接收连接↓Poller/Processor解析HTTP↓封装为Request/Response↓CoyoteAdapter适配到Servlet API

3.2 Mapper组件的URL映射机制

Mapper 的作用是根据 URL 找到正确的 Servlet。

  • 匹配规则(从粗到细):

    1. 匹配 Host(域名)

    2. 匹配 Context(Web 应用路径)

    3. 匹配 Wrapper(Servlet 映射规则)

例如访问 http://localhost:8080/demo/hello

  • Host:localhost

  • Context:/demo

  • Wrapper:匹配到 /hello 的 Servlet

关键类:
  • org.apache.catalina.mapper.Mapper

  • org.apache.catalina.core.StandardHost

  • org.apache.catalina.core.StandardContext


3.3 Pipeline-Valve机制:请求过滤与处理链

Tomcat 的容器(Engine、Host、Context、Wrapper)都有一个 Pipeline(管道),里面装着多个 Valve(阀门)。

  • Pipeline:请求处理的有序链路。

  • Valve:具体的处理步骤,例如日志记录、安全检查、压缩等。

  • 基本原则:请求会沿着 Valve 链从上到下传递,最终交给 Servlet 处理。

示例:默认Valve链
EnginePipeline→ HostPipeline→ ContextPipeline→ WrapperPipeline→ StandardWrapperValve(最终调用Servlet.service())
可自定义Valve示例:
public class MyLogValve extends ValveBase {@Overridepublic void invoke(Request request, Response response) throws IOException, ServletException {System.out.println("请求URI: " + request.getRequestURI());getNext().invoke(request, response); // 继续下一个Valve}
}

server.xml 中注册即可生效。


3.4 Servlet的加载与执行(Wrapper → Servlet实例)

  1. Wrapper找到Servlet
    Mapper 找到的目标是某个 Wrapper,Wrapper 中保存了 Servlet 的配置信息。

  2. Servlet加载

    • 如果 Servlet 未被加载,StandardWrapper 会调用 loadServlet() 创建并初始化 Servlet 实例(调用 init() 方法)。

  3. 执行Servlet

    • 最终由 StandardWrapperValve 调用 Servlet.service(),根据请求方法分发到 doGet()doPost() 等方法。

  4. 返回响应

    • Servlet 处理完成后,将数据写入 HttpServletResponse,由 Connector 发送回客户端。


✅ 本章小结

  • Connector:接收 Socket 连接并解析协议。

  • CoyoteAdapter:适配成 Servlet API。

  • Mapper:根据 URL 定位到具体 Servlet。

  • Pipeline-Valve:处理链路,可扩展。

  • Wrapper:管理 Servlet 的生命周期并调用其方法。

第四章:性能优化与调优


4.1 I/O模型选择与性能对比

Tomcat 支持多种 I/O 模型,选择合适的模型是性能优化的第一步。

I/O 模型协议类名特点适用场景
BIO(阻塞I/O)Http11Protocol简单稳定,但每个请求一个线程,连接多时性能差老系统、小并发
NIO(非阻塞I/O)Http11NioProtocol单线程管理多个连接,性能好,JDK自带推荐默认
NIO2(异步I/O)Http11Nio2ProtocolJDK7+,AIO模型,适合高并发高吞吐场景
APR(本地库)Http11AprProtocol使用Apache Portable Runtime,接近C语言性能需要原生库,追求极限性能

切换示例server.xml):

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"maxThreads="500" connectionTimeout="20000"/>

4.2 线程池配置调优策略

Tomcat 的 Connector 内部有线程池,决定了同时能处理多少请求。

  • 核心参数

    • maxThreads:最大工作线程数(默认200)

    • minSpareThreads:启动时的最小空闲线程数(默认10)

    • acceptCount:队列长度,满了会拒绝请求(默认100)

    • connectionTimeout:连接超时时间(毫秒)

调优思路

  1. 根据 CPU 核数和业务特性,计算合适的线程数(CPU 密集型:2×核数;I/O 密集型:更高)。

  2. 压测观察线程池是否饱和,必要时增加 acceptCount 避免拒绝连接。

  3. 调短 connectionTimeout 以减少无效连接占用。

配置示例

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"maxThreads="800"minSpareThreads="50"acceptCount="300"connectionTimeout="15000"/>

4.3 内存泄漏问题与解决方案

Tomcat 在长时间运行中,可能因类加载器或未关闭的资源造成 PermGen/Metaspace 泄漏

常见原因:

  • Web 应用热部署后,老的 ClassLoader 未释放。

  • JDBC 连接、线程池、定时任务未关闭。

  • 静态集合引用持有大对象。

解决策略:

  • 禁用频繁热部署,生产中使用全量重启。

  • ServletContextListener.contextDestroyed() 中手动关闭资源。

  • 启用 org.apache.catalina.loader.WebappClassLoaderBase 的内存泄漏检测日志:

    <Context reloadable="false"><Loader leakDetection="true"/>
    </Context>
    

4.4 高并发场景下的配置优化案例

假设业务是一个 高并发API服务,每天有数百万请求,可以做如下优化:

  1. 启用NIO模型,提升多连接处理能力。

  2. 加大线程池

    maxThreads="1000" minSpareThreads="100" acceptCount="500"
    

  3. 压缩响应(减少网络传输量):

    compression="on" compressionMinSize="1024"
    compressableMimeType="text/html,text/xml,text/plain,application/json"
    

  4. Keep-Alive优化

    maxKeepAliveRequests="100" keepAliveTimeout="5000"
    

  5. 反向代理配合(Nginx + Tomcat):

    • Nginx 负责 SSL 终端和静态资源。

    • Tomcat 专注处理动态请求,减少负载。

第五章:实战案例与代码示例


5.1 自定义 Valve 实现请求日志记录

场景:我们希望记录每个 HTTP 请求的 URI 和处理耗时,这可以帮助排查性能问题。

代码实现
server.xml 中注册:
package com.example.tomcat;import org.apache.catalina.Request;
import org.apache.catalina.Response;
import org.apache.catalina.Valve;
import org.apache.catalina.valves.ValveBase;import javax.servlet.ServletException;
import java.io.IOException;public class MyLogValve extends ValveBase {@Overridepublic void invoke(Request request, Response response) throws IOException, ServletException {long start = System.currentTimeMillis();String uri = request.getRequestURI();System.out.println("[MyLogValve] 请求URI: " + uri);// 调用下一个Valve或最终的ServletgetNext().invoke(request, response);long duration = System.currentTimeMillis() - start;System.out.println("[MyLogValve] 请求耗时: " + duration + "ms");}
}

这样,所有到 localhost 的请求都会被我们的日志 Valve 拦截并记录。


5.2 server.xml 配置优化示例

假设我们要优化一个高并发 API 服务的 Tomcat:

<Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true"><Valve className="com.example.tomcat.MyLogValve"/>
</Host>

优化要点

  • NIO 模型:提升连接并发能力。

  • 线程池加大:应对高并发。

  • 响应压缩:减少网络带宽消耗。

  • Keep-Alive 优化:避免连接长时间占用。


5.3 Servlet 生命周期代码演示

场景:展示 Servlet 的 init()service()destroy() 调用时机。

示例代码:
package com.example.servlet;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class LifeCycleServlet extends HttpServlet {@Overridepublic void init() throws ServletException {System.out.println("[Servlet] init() - 初始化Servlet");}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {System.out.println("[Servlet] service() - 处理请求: " + req.getMethod());resp.getWriter().write("Hello, this is LifeCycleServlet");}@Overridepublic void destroy() {System.out.println("[Servlet] destroy() - 销毁Servlet");}
}
web.xml 配置:
<servlet><servlet-name>lifeCycleServlet</servlet-name><servlet-class>com.example.servlet.LifeCycleServlet</servlet-class><load-on-startup>1</load-on-startup>
</servlet><servlet-mapping><servlet-name>lifeCycleServlet</servlet-name><url-pattern>/lifecycle</url-pattern>
</servlet-mapping>

运行结果

  1. 第一次访问 /lifecycle 时触发 init()

  2. 每次请求调用 service()

  3. Tomcat 关闭时调用 destroy()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919078.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919078.shtml
英文地址,请注明出处:http://en.pswp.cn/news/919078.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java web】HTTP 协议详解

一、什么是 HTTP&#xff1f;—— 互联网的 "快递员"你有没有想过&#xff0c;当你在浏览器输入www.baidu.com并按下回车时&#xff0c;背后发生了什么&#xff1f;为什么几秒钟后就能看到百度首页&#xff1f;这一切的背后&#xff0c;都离不开一个叫HTTP的 "快…

流式数据服务端怎么传给前端,前端怎么接收?

01 引言 大模型时代&#xff0c;尤其会话模型为了提高用户的使用体验&#xff0c;它不会将所有的数据加载完成一次响应给客户端&#xff0c;而是通过数据流&#xff0c;一点点的将数据慢慢呈现出来。 正是这种有趣的交互方式一次次将SSE&#xff08;Server Sent Event&#x…

ML307C 4G通信板:工业级DTU固件,多协议支持,智能配置管理

产品概述 ML307C 4G通信板是一款基于中移物联网ML307C模组的工业级DTU&#xff08;数据传输单元&#xff09;产品&#xff0c;专为工业物联网应用设计。我们的固件支持多种工业协议&#xff0c;具备远程配置、FOTA升级、数据加密等企业级功能&#xff0c;为您的工业设备提供稳定…

Sublime配置verilog开发环境-具备语法高亮、代码补全、自定义代码段及语法检查等功能,提升FPGA开发效率!

对于在学习FPGA开发之前使用过其他集成开发工具如VS、pycharm、keil或编辑工具如Sublime、VScode、Notepad的朋友&#xff0c;在使用Vivado时可能会像博主一样感觉自带编辑器用起来不太舒服&#xff0c;比如不支持语法高亮显示&#xff0c;不支持代码自动补全等功能。因次&…

18_基于深度学习的烟雾检测识别系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)

目录 项目介绍&#x1f3af; 功能展示&#x1f31f; 一、环境安装&#x1f386; 环境配置说明&#x1f4d8; 安装指南说明&#x1f3a5; 环境安装教学视频 &#x1f31f; 二、数据集介绍&#x1f31f; 三、系统环境&#xff08;框架/依赖库&#xff09;说明&#x1f9f1; 系统环…

【计算机网络架构】混合型架构简介

引言在当今数字化浪潮席卷全球的背景下&#xff0c;网络技术正以前所未有的速度迅猛发展&#xff0c;各种网络架构如雨后春笋般涌现。从早期简单的总线型、星型架构&#xff0c;到后来的环型、树型架构&#xff0c;再到如今复杂的网状型、云计算架构等&#xff0c;每一种架构都…

Hexo 双分支部署指南:从原理到 Netlify 实战

Hexo 双分支部署指南&#xff1a;从原理到 Netlify 实战 在 Hexo 博客部署中&#xff0c;很多人会困惑于hexo d自动部署与 GitHub 手动提交的区别&#xff0c;以及如何通过双分支结构优雅地部署到 Netlify。本文将清晰拆解两种部署方式的核心差异&#xff0c;并手把手教你用双分…

【数据结构】深入理解单链表与通讯录项目实现

文章目录一、单链表的概念及结构1.1 什么是单链表&#xff1f;1.2 节点的组成1.3 单链表的特点二、单链表的实现2.1 类型定义2.2 基础工具函数1. 链表打印函数2. 节点创建函数2.3 单链表的核心操作&#xff08;1&#xff09;插入操作1. 尾插&#xff08;SLTPushBack&#xff09…

《Python学习之字典(一):基础操作与核心用法》

坚持用 清晰易懂的图解 代码语言&#xff0c;让每个知识点变得简单&#xff01; &#x1f680;呆头个人主页详情 &#x1f331; 呆头个人Gitee代码仓库 &#x1f4cc; 呆头详细专栏系列 座右铭&#xff1a; “不患无位&#xff0c;患所以立。” Python学习之字典&#xff08;…

[安洵杯 2019]Attack

BUUCTF在线评测BUUCTF 是一个 CTF 竞赛和训练平台&#xff0c;为各位 CTF 选手提供真实赛题在线复现等服务。https://buuoj.cn/challenges#[%E5%AE%89%E6%B4%B5%E6%9D%AF%202019]Attack流量分析题&#xff0c;浏览的时候发现攻击者上传信息页面&#xff0c; 直接搜索 flag 就…

复合机器人食品分拣生产线:一体化控制系统引领高效柔性新食代

在食品工业高速发展的今天&#xff0c;面对种类繁多、形态各异的原料分拣需求&#xff0c;以及日益严格的卫生安全与效率要求&#xff0c;传统的固定式分拣设备已难以胜任。复合机器人食品分拣生产线凭借其融合移动&#xff08;AMR&#xff09;与操作&#xff08;机械臂&#x…

二十七、动态SQL

动态SQL介绍动态SQL&#xff1a;if与where标签动态案例-动态更新EmpMapper&#xff08;接口&#xff09;中对应代码块 //动态更新员工public void update2(Emp emp);EmpMapper.xml中对应代码块 <!-- 动态更新员工--><update id"update2">update emp<s…

AI可行性分析:数据×算法×反馈=成功

3.1 从场景到AI可行性分析:需求拆解为“数据+算法+反馈” 核心公式: AI可行性 = 数据可获得性 算法适配性 反馈闭环性 (任一要素为0则需求不可行) 一、传统需求 vs AI需求本质差异 需求文档对比(电商案例) 维度 传统需求文档(购物车功能) AI需求文档(商品推荐系…

【图论】分层图 / 拆点

大多数都是同一个套路&#xff0c;将图拆开成几个图&#xff0c;每一层都对应着一个不同的状态&#xff0c;比如把到点 i 的状态拆成经过了 j 次操作所得的 xx 结果&#xff0c;一般数据不会很大 目前遇到的可分为 3 类&#xff1a; ①.给你最多 k 次操作&#xff0c;求 xx 结…

VS Code配置MinGW64编译MATIO库

VS Code 使用 MinGW64 编译 C 代码并配置 MATIO 库的完整步骤 1. 安装 MSYS2 下载 MSYS2 访问 MSYS2 官网下载安装包&#xff08;选择 x86_64 版本&#xff09;默认安装路径&#xff1a;C:\msys64 更新 MSYS2 包数据库 打开 MSYS2 MinGW 64-bit&#xff08;注意不是 MSYS&…

【前端Vue】使用ElementUI实现表单中可选择可编辑的下拉框

由于项目在vue的开发框架下&#xff0c;因此使用ElementUI组件库进行实现。我希望可选择可编辑的下拉框右侧有跟下拉框一样的箭头&#xff0c;并且在未输入任何内容时&#xff0c;点击该框体会出现选择列表进行填充数据的选择&#xff0c;点击选中数据后列表消失&#xff0c;数…

每日五个pyecharts可视化图表-line:从入门到精通 (4)

欢迎来到pyecharts折线图系列的第四篇文章&#xff01;在前三篇中&#xff0c;我们已经掌握了多种折线图类型&#xff0c;包括基本折线图、平滑折线图、雨量流量关系图、多X轴折线图、堆叠区域图和阶梯图等。在本文中&#xff0c;我们将继续探索五种更高级的折线图类型&#xf…

MySQL中的字符串函数

目录 一、字符串【分割】函数&#xff1a;SUBSTRING_INDEX() SUBSTRING_INDEX函数 练习题 统计每种性别的人数 提取博客URL中的用户名 截取出年龄 SQL83 商品id数据清洗统计 SQL250 查找字符串中逗号出现的次数 二、字符串【截取】函数&#xff1a;SUBSTRING() 基本语…

CodeBuddy IDE深度体验:AI驱动的全栈开发新时代

在人工智能技术迅猛发展的今天&#xff0c;开发者工具正在经历一场深刻的变革。腾讯推出的CodeBuddy IDE作为全球首个“产设研一体”的AI全栈高级工程师工具&#xff0c;重新定义了开发者的日常工作流程。 从需求分析到设计、编码、部署&#xff0c;CodeBuddy通过AI能力将传统…

实现Android图片手势缩放功能的完整自定义View方案,结合了多种手势交互功能

主要功能特点&#xff1a;支持双指手势缩放图片&#xff0c;通过ScaleGestureDetector实现平滑的缩放效果25双击图片可切换初始大小和中等放大比例16使用Matrix进行图像变换&#xff0c;保持缩放中心点为手势焦点位置57自动缩放动画通过Runnable实现渐进式变化1限制最小和最大缩…