Tomcat 全面学习笔记

第一章:Tomcat 概述

1.1 Web 服务器与应用服务器

  • Web 服务器:核心处理 HTTP 协议,主要负责静态资源(HTML、CSS、JS、图片)的请求响应,反向代理、负载均衡,无法直接处理动态业务逻辑与 Java 代码。代表产品:Nginx、Apache HTTP Server。
  • 应用服务器:基于特定语言规范(如 Java EE/Jakarta EE),提供完整的业务逻辑运行环境,支持组件管理、事务控制、数据库连接池、消息队列等企业级特性,可处理动态资源请求。代表产品:WildFly、GlassFish、WebLogic。
  • 核心区别 :Web 服务器专注 HTTP 通信与静态资源处理;应用服务器提供业务运行的全栈容器能力,Tomcat 是介于两者之间的Servlet 容器,也被称为轻量级应用服务器。

1.2 Tomcat 简介与定位

Apache Tomcat 是 Apache 软件基金会旗下的开源 Java Web 容器,完全实现了Servlet、JSP、EL 表达式、WebSocket等 Jakarta EE(原 Java EE)核心规范,是 Java Web 开发的主流运行环境。

  • 核心定位:不是完整的 Jakarta EE 企业级服务器(不支持 EJB、JTA 等规范),而是专注于 Servlet/JSP 规范的轻量级 Web 容器,兼顾 HTTP 服务器能力与 Java 动态代码运行能力。
  • 核心优势:开源免费、轻量高效、稳定性强、生态完善、社区活跃,兼容主流 Java 开发框架(Spring、Spring Boot、MyBatis 等),是中小规模 Java Web 项目与微服务架构的首选容器。

1.3 Tomcat 版本发展历史

Tomcat 版本与 JDK、Servlet/JSP 规范强绑定,核心稳定版本及关键特性如下:

表格

Tomcat 版本 规范支持 最低 JDK 要求 核心特性与里程碑
8.5.x Servlet 3.1、JSP 2.3 JDK 7+ 移除 BIO 连接器,支持 HTTP/2,优化 NIO 性能,长期维护版本
9.0.x Servlet 4.0、JSP 2.3 JDK 8+ 支持 HTTP/2 全特性,TLS 1.3,生命周期优化,目前最广泛使用的稳定版
10.0.x Servlet 5.0、JSP 3.0 JDK 8+ 完成从 Java EE 到 Jakarta EE 的迁移,核心包名从javax.*改为jakarta.*
10.1.x Servlet 6.0、JSP 3.1 JDK 11+ 支持 Jakarta EE 10,JDK 17 兼容优化,当前主流维护版本
11.0.x Servlet 6.1、JSP 4.0 JDK 17+ 最新稳定版,支持虚拟线程,性能大幅优化,适配 JDK 21+

关键注意点:Tomcat 10 及以上版本使用jakarta.*包名,与 Spring Boot 3.x、Spring 6.x 适配;Tomcat 9 及以下使用javax.*包名,适配 Spring Boot 2.x、Spring 5.x,不可混用,否则会出现类加载异常。

1.4 与其他 Java Web 服务器的比较

表格

服务器 核心定位 优势 劣势 适用场景
Tomcat 轻量级 Servlet 容器 轻量、开源、易上手、生态完善、资源占用低 不支持完整 Jakarta EE 规范,企业级特性需扩展 中小项目、微服务、Spring Boot 默认容器、开发测试环境
Jetty 嵌入式轻量级 Servlet 容器 极致轻量、模块化设计、嵌入式支持更友好、启动速度快 生态成熟度略低于 Tomcat,企业级案例较少 嵌入式场景、网关、轻量级微服务、资源受限环境
WildFly(JBoss) 全栈 Jakarta EE 应用服务器 支持完整企业级规范、集群能力强、事务 / 安全特性完善 重量级、资源占用高、学习成本高 大型企业级项目、需要完整 Java EE 特性的单体应用
GlassFish Jakarta EE 官方参考实现 完全兼容最新 Jakarta EE 规范、官方标准参考 性能一般、社区活跃度低、生产环境案例少 规范学习、测试验证,不推荐生产环境使用
WebLogic 商业企业级应用服务器 极致稳定性、超强集群与容灾能力、商业级技术支持 闭源收费、重量级、部署运维复杂 金融、电信等超大型企业核心业务系统

第二章:Tomcat 安装与配置

2.1 环境要求(JDK 版本)

Tomcat 运行强依赖 Java 环境,必须提前安装对应版本的 JDK/JRE,核心匹配规则如下:

  • Tomcat 9.0.x:最低 JDK 8,推荐 JDK 8/11(LTS 版本)
  • Tomcat 10.0.x:最低 JDK 8,推荐 JDK 11/17
  • Tomcat 10.1.x:最低 JDK 11,推荐 JDK 17/21
  • Tomcat 11.0.x:最低 JDK 17,推荐 JDK 21/25

验证命令:安装完成后执行java -version,确保 JDK 环境正常,且配置了JAVA_HOME环境变量(Tomcat 启动时会优先读取该变量)。

2.2 Windows/Linux/Mac 安装方式

Tomcat 提供绿色解压版安装包,跨平台通用,核心安装步骤如下:

1. 通用前置步骤

从 Apache Tomcat 官网(https://tomcat.apache.org/)下载对应版本的压缩包:

  • Windows:apache-tomcat-xxx.zip
  • Linux/Mac:apache-tomcat-xxx.tar.gz
2. Windows 安装
  1. 解压压缩包到无中文、无空格的目录(如D:\apache-tomcat-9.0.89
  2. 配置环境变量(可选):新建CATALINA_HOME,值为解压根目录
  3. 启动验证:进入bin目录,双击startup.bat,弹出命令行无报错,浏览器访问http://localhost:8080出现 Tomcat 默认首页即为成功。
3. Linux 安装
  1. 上传压缩包到服务器,执行解压命令:tar -zxvf apache-tomcat-xxx.tar.gz -C /usr/local/
  2. 配置环境变量(可选):编辑/etc/profile,添加export CATALINA_HOME=/usr/local/apache-tomcat-xxx,执行source /etc/profile生效
  3. 赋予执行权限:chmod +x $CATALINA_HOME/bin/*.sh
  4. 启动验证:执行$CATALINA_HOME/bin/startup.sh,浏览器访问http://服务器IP:8080出现默认首页即为成功(需提前开放防火墙 8080 端口)。
4. Mac 安装
  • 方式 1(解压版):与 Linux 步骤完全一致,解压后赋予脚本执行权限,执行startup.sh启动。
  • 方式 2(Homebrew):执行brew install tomcat,自动完成安装与环境配置,执行catalina start启动。

2.3 目录结构解析

Tomcat 解压后的根目录为CATALINA_HOME,核心目录及作用如下:

表格

目录 核心作用 关键说明
bin 启停脚本与核心工具 存放 Windows/Linux 启停脚本(startup/startup.bat、shutdown/shutdown.bat)、catalina 脚本(核心启动入口)、版本查看脚本等
conf 核心配置文件目录 Tomcat 全局配置存放地,包含 server.xml、web.xml、tomcat-users.xml 等所有核心配置文件,是运维核心目录
lib 核心依赖库目录 存放 Tomcat 自身运行所需的所有 jar 包,以及全局共享的 jar 包,所有 Web 应用均可加载该目录下的类
logs 日志文件目录 存放 Tomcat 运行日志、访问日志、错误日志,默认包含 catalina.out(控制台输出日志)、localhost_access_log.*.txt(访问日志)等
webapps 默认应用部署目录 Web 应用的默认部署目录,放入该目录的 WAR 包 / 解压后的 Web 应用会被 Tomcat 自动加载部署,默认包含 ROOT、manager、docs 等自带应用
work 临时工作目录 存放 JSP 编译生成的 Servlet 字节码文件,清空该目录可解决 JSP 缓存问题
temp 临时文件目录 存放 Tomcat 运行过程中产生的临时文件,可定期清理

2.4 启动、停止与重启操作

核心启停脚本说明

所有启停操作均通过bin目录下的脚本执行,核心脚本为catalina.sh(Linux/Mac)/catalina.bat(Windows),startup/shutdown脚本是对 catalina 脚本的封装。

表格

操作 Linux/Mac 命令 Windows 命令 补充说明
前台启动 ./catalina.sh run catalina.bat run 控制台输出日志,关闭窗口即停止服务,适合调试
后台启动 ./startup.sh startup.bat 后台运行服务,日志输出到 logs/catalina.out,生产环境常用
正常停止 ./shutdown.sh shutdown.bat 优雅停止,等待所有请求处理完成、资源释放后关闭服务
强制停止 kill -9 进程号 任务管理器结束 java 进程 异常卡死时使用,可能导致数据丢失、请求中断,不推荐常规使用
重启 先执行 shutdown.sh,再执行 startup.sh 先执行 shutdown.bat,再执行 startup.bat 生产环境建议先停止,确认进程退出后再启动,避免端口占用

关键注意:Linux 环境下,停止服务后需执行ps -ef | grep tomcat确认进程已退出,避免残留进程导致重启端口占用。

2.5 端口修改与多实例部署

1. 端口修改

Tomcat 默认占用 3 个核心端口,均在conf/server.xml中修改,修改后需重启服务生效:

  • 8080 :HTTP 服务默认端口,Connector 节点的port属性,修改为其他未占用端口即可(如 80)。
  • 8005 :Shutdown 关闭端口,Server 节点的port属性,用于接收停止服务的指令,生产环境建议修改。
  • 8009 :AJP 协议默认端口,Connector 节点(protocol="AJP/1.3")的port属性,不与 Apache 集成时建议注释禁用。

示例:修改 HTTP 端口为 80

xml

复制代码
<!-- 原配置 -->
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<!-- 修改后 -->
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
2. 多实例部署

多实例指在同一台服务器上,基于同一个CATALINA_HOME(Tomcat 安装目录),启动多个独立的 Tomcat 进程,实现资源隔离、端口隔离、应用隔离。核心原理:Tomcat 启动时,CATALINA_HOME为程序安装目录,CATALINA_BASE为实例工作目录,每个实例使用独立的CATALINA_BASE,共享CATALINA_HOME的程序与依赖。

部署步骤:

  1. 新建实例目录,如/usr/local/tomcat-instance1/usr/local/tomcat-instance2

  2. 每个实例目录下,复制CATALINA_HOME中的conflogstempwebappswork5 个目录

  3. 修改每个实例conf/server.xml中的 3 个核心端口,确保所有实例端口不冲突

  4. 启动实例:指定CATALINA_BASE执行启动脚本

    bash

    复制代码
    # 启动实例1
    export CATALINA_BASE=/usr/local/tomcat-instance1
    $CATALINA_HOME/bin/startup.sh
    
    # 启动实例2
    export CATALINA_BASE=/usr/local/tomcat-instance2
    $CATALINA_HOME/bin/startup.sh

第三章:配置文件详解

Tomcat 的所有核心配置均在conf目录下,本章详解核心配置文件的作用、核心节点与配置规范。

3.1 server.xml 核心配置

server.xml是 Tomcat 的核心配置文件,定义了 Tomcat 的整体架构、服务、连接器、容器等核心组件,配置层级为:Server -> Service -> Connector -> Engine -> Host -> Context

核心层级节点详解
  1. Server 节点 :Tomcat 顶层节点,代表整个 Servlet 容器实例,一个server.xml只能有一个 Server 节点。

    • 核心属性:port(关闭端口,默认 8005)、shutdown(关闭指令字符串,生产环境建议修改为复杂字符串)
    • 作用:监听关闭指令,管理所有 Service 组件的生命周期。
  2. Service 节点:Server 的子节点,代表一个独立的服务集合,一个 Server 可包含多个 Service 节点,实现服务隔离。

    • 核心属性:name(服务名称,默认 Catalina)
    • 作用:绑定一个 Engine 容器与多个 Connector 连接器,实现连接器与容器的关联。
  3. Engine 节点:Service 的子节点,一个 Service 只能有一个 Engine,是请求处理的核心引擎,负责接收并分发所有连接器的请求到对应的虚拟主机。

    • 核心属性:name(引擎名称)、defaultHost(默认虚拟主机,必须与下属 Host 节点的 name 一致,默认localhost
    • 作用:请求路由的核心,根据请求的域名分发到对应的 Host 虚拟主机。
  4. Host 节点:Engine 的子节点,代表虚拟主机,一个 Engine 可包含多个 Host 节点,实现多个域名映射到同一个 Tomcat 实例。

    • 核心属性:name(虚拟主机域名,如www.test.com)、appBase(该虚拟主机的应用部署目录,默认 webapps)、autoDeploy(是否开启自动部署,默认 true)、unpackWARs(是否自动解压 WAR 包,默认 true)
    • 作用:管理该域名下的所有 Web 应用(Context),接收引擎分发的对应域名的请求。
  5. Context 节点:Host 的子节点,代表一个独立的 Web 应用,一个 Host 可包含多个 Context 节点,每个 Context 对应一个 Web 应用。

    • 核心属性:path(应用访问路径,如/test,根路径为"")、docBase(应用的物理路径,绝对路径或相对 appBase 的路径)、reloadable(是否开启 class 文件热加载,默认 false,生产环境建议关闭)
    • 作用:Web 应用的运行上下文,加载应用的部署描述符,管理应用的生命周期与类加载器。
连接器类型(HTTP/1.1, AJP)

Connector 是 Service 的子节点,负责接收客户端请求,封装为 ServletRequest 对象传递给 Engine 容器,一个 Service 可配置多个 Connector,支持不同协议与端口。

  1. HTTP/1.1 连接器

    • 核心作用:处理 HTTP/HTTPS 协议的客户端请求,是 Tomcat 最核心、最常用的连接器,默认配置在 8080 端口。
    • 核心属性:port(监听端口)、protocol(IO 模型,默认HTTP/1.1,对应 NIO 模型)、connectionTimeout(连接超时时间,单位毫秒,默认 20000)、redirectPort(HTTPS 重定向端口,默认 8443)、maxThreads(最大线程数)、URIEncoding(URI 编码格式,建议 UTF-8)。
    • 适用场景:直接对外提供 HTTP 服务、与 Nginx 反向代理集成(HTTP 模式)。
  2. AJP 连接器

    • 核心作用:处理 AJP(Apache JServ Protocol)协议请求,是面向二进制的 TCP 协议,比 HTTP 协议性能更高,专门用于 Tomcat 与 Apache/Nginx 等 Web 服务器的集成。
    • 核心属性:port(默认 8009)、protocolAJP/1.3)、secretRequired(是否需要密钥认证,高版本默认开启)、secret(密钥字符串)。
    • 适用场景:与 Apache HTTP Server 深度集成、需要保留客户端原始请求信息的场景;不与前端 Web 服务器集成时,建议注释禁用,减少安全风险。

3.2 web.xml 部署描述符

conf/web.xml是 Tomcat 的全局部署描述符 ,对所有部署的 Web 应用生效,每个 Web 应用的WEB-INF/web.xml是应用私有配置,会覆盖全局配置的同名项。

核心配置内容:

  1. 默认 Servlet 配置 :定义了 Tomcat 内置的两个核心 Servlet
    • DefaultServlet:处理静态资源请求,是 Tomcat 静态资源处理的核心,可配置缓存、目录浏览、默认文件等。
    • JspServlet:处理 JSP 请求,负责 JSP 文件的编译与执行,可配置 JSP 编译参数、开发模式、缓存等。
  2. MIME 类型映射:定义了文件后缀与 MIME 类型的对应关系,浏览器根据 MIME 类型解析文件,可自定义新增 MIME 类型。
  3. 欢迎页配置 :默认欢迎页列表,优先级从高到低为index.htmlindex.htmindex.jsp,应用可在私有 web.xml 中覆盖。
  4. 错误页配置:全局默认错误页映射,可根据 HTTP 状态码或异常类型配置对应的错误处理页面。
  5. 会话超时配置:全局默认 Session 超时时间,单位分钟,默认 30 分钟,应用可私有配置覆盖。
  6. 安全约束配置:全局的资源访问权限约束,可配置禁止访问的资源、认证方式等。

3.3 context.xml 上下文配置

conf/context.xml是 Tomcat 的全局上下文配置 ,对所有部署的 Web 应用生效,每个应用可通过META-INF/context.xml私有配置覆盖。

核心配置内容:

  1. 资源配置 :全局的 JNDI 资源定义,如数据库连接池、JavaMail 会话、自定义资源等,所有应用可直接通过 JNDI 查找使用。示例:全局数据库连接池配置

    xml

    复制代码
    <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
              maxTotal="100" maxIdle="30" maxWaitMillis="10000"
              username="root" password="123456" driverClassName="com.mysql.cj.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/test?useSSL=false&amp;serverTimezone=UTC"/>
  2. 容器配置 :配置 Web 应用的上下文行为,如antiResourceLocking(防资源锁定)、cachingAllowed(是否允许静态资源缓存)、sessionCookiePath(Session Cookie 路径)等。

  3. Valve 阀门配置:全局的 Valve 组件配置,对所有应用生效,如访问日志、IP 黑白名单、请求过滤等。

  4. Jar 包扫描配置:配置 Tomcat 启动时跳过扫描的 Jar 包,减少启动时间,解决 Jar 包冲突问题。

3.4 日志配置(logging.properties)

conf/logging.properties是 Tomcat 的日志配置文件,基于 Java 原生的 JUL(java.util.logging)日志框架实现,控制 Tomcat 自身的日志输出级别、输出路径、格式等。

核心配置内容:

  1. 全局日志级别.level = INFO,定义 Tomcat 全局默认日志级别,优先级从高到低为:SEVERE(错误)> WARNING(警告)> INFO(信息)> CONFIG(配置)> FINE> FINER> FINEST(调试),级别越低,输出日志越详细。
  2. 处理器 Handler 配置 :定义日志的输出方式,默认包含:
    • java.util.logging.ConsoleHandler:控制台输出,对应 catalina.out 文件。
    • java.util.logging.FileHandler:文件输出,按类别生成日志文件(如localhost.log、catalina.log)。
  3. 自定义组件日志级别 :可针对特定组件配置独立的日志级别,如开启容器调试日志:org.apache.catalina.core.level = FINE
  4. 日志格式配置 :通过java.util.logging.SimpleFormatter.format配置日志输出格式,自定义时间、线程、级别、类名、日志内容的展示规则。
  5. 日志文件配置:配置日志文件的存储路径、文件名、最大大小、保留天数等。

3.5 用户权限配置(tomcat-users.xml)

conf/tomcat-users.xml是 Tomcat 的用户与权限配置文件,用于配置用户、角色、权限映射,控制 Tomcat 管理界面(Manager App、Host Manager)的访问权限,基于内存域(MemoryRealm)实现认证。

核心配置规则:

  1. 角色配置 :通过<role>标签定义角色,rolename为角色名称,Tomcat 内置了管理界面的专用角色:

    表格

    角色名 权限范围
    manager-gui 访问 Manager App 图形化管理界面,查看应用状态、部署 / 卸载应用
    manager-script 访问 Manager App 脚本接口,用于命令行 / 脚本部署应用
    manager-jmx 访问 JMX 代理接口,用于监控管理
    manager-status 只读权限,仅可查看 Tomcat 状态与应用状态
    admin-gui 访问 Host Manager 图形化界面,管理虚拟主机
    admin-script 访问 Host Manager 脚本接口
  2. 用户配置 :通过<user>标签定义用户,username为用户名,password为密码,roles为用户绑定的角色,多个角色用逗号分隔。

完整配置示例:

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
    <!-- 定义角色 -->
    <role rolename="manager-gui"/>
    <role rolename="manager-status"/>
    <role rolename="admin-gui"/>
    <!-- 定义管理员用户,绑定多个角色 -->
    <user username="tomcat-admin" password="Admin@123456" roles="manager-gui,admin-gui,manager-status"/>
    <!-- 定义只读用户 -->
    <user username="tomcat-monitor" password="Monitor@123" roles="manager-status"/>
</tomcat-users>

安全注意:生产环境必须修改默认用户名密码,使用强密码,最小化权限分配,禁止给用户分配不必要的角色,同时限制管理界面的访问 IP。

第四章:Tomcat 架构与组件

4.1 Tomcat 整体架构

Tomcat 的核心设计是模块化、松耦合,整体架构分为两大核心模块,以及多个辅助组件,整体架构如下:

plaintext

复制代码
┌─────────────────────────────────────────────────────────┐
│                    客户端(浏览器/其他服务)              │
└───────────────────────────┬─────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│                Coyote 连接器模块(核心)                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ HTTP连接器  │  │ AJP连接器   │  │ HTTPS连接器 │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
│  作用:监听网络端口,接收客户端请求,解析协议,封装请求   │
│  为标准ServletRequest对象,传递给Catalina容器处理       │
└───────────────────────────┬─────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│               Catalina  Servlet容器模块(核心)           │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐     │
│  │ Engine  │→ │  Host   │→ │ Context │→ │ Wrapper │     │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘     │
│  作用:Servlet容器核心,负责请求的分发、Servlet的加载与  │
│  执行、生命周期管理、类加载、资源管理等核心业务逻辑       │
└─────────────────────────────────────────────────────────┘
  • Coyote 连接器:是 Tomcat 与外界的通信入口,负责网络通信、协议解析,屏蔽了网络层与协议层的差异,为 Catalina 容器提供统一的 ServletRequest 对象。
  • Catalina 容器:是 Tomcat 的核心,实现了 Servlet 规范,负责管理 Servlet 的生命周期、请求处理、资源管理、集群、安全等所有核心功能,采用层级化的容器设计,层层嵌套,职责单一。
  • 其他辅助模块:Jasper 模块(JSP 编译引擎)、Naming 模块(JNDI 命名服务)、Session 模块(会话管理)、Security 模块(安全认证授权)、Cluster 模块(集群管理)等。

4.2 核心组件详解

Tomcat 的 Catalina 容器采用层级化设计,核心组件从顶层到底层依次为:Server → Service → Engine → Host → Context → Wrapper,每个组件各司其职,形成父子容器关系,下层组件继承上层组件的生命周期与配置。

1. Server
  • 顶层组件,代表整个 Tomcat 实例,一个 JVM 进程中只有一个 Server 实例。
  • 核心职责:
    1. 管理所有 Service 组件的生命周期,负责 Service 的初始化、启动、停止、销毁。
    2. 监听 Shutdown 端口,接收关闭指令,优雅关闭整个 Tomcat 实例。
    3. 维护全局的 JNDI 命名服务,管理全局资源配置。
2. Service
  • Server 的子组件,一个 Server 可包含多个 Service,每个 Service 是独立的服务单元,相互隔离。
  • 核心职责:
    1. 作为连接器与容器的桥梁,将多个 Connector 连接器绑定到一个 Engine 引擎。
    2. 管理下属 Connector 与 Engine 的生命周期,统一启动与停止。
    3. 实现多服务隔离,例如一个 Service 处理对外 HTTP 请求,另一个 Service 处理内部 AJP 请求,互不干扰。
3. Connector
  • Service 的子组件,一个 Service 可包含多个 Connector,每个 Connector 对应一个端口与协议,是 Tomcat 的通信入口。
  • 核心职责:
    1. 监听指定端口,接收客户端的 TCP 连接,管理连接的生命周期。
    2. 解析对应协议(HTTP/AJP/HTTPS),将原始请求封装为标准的 ServletRequest 对象。
    3. 将封装后的请求传递给绑定的 Engine 引擎处理,处理完成后将响应结果返回给客户端。
    4. 管理 IO 模型(NIO/NIO2/APR)、线程池、连接数、超时等网络相关配置。
4. Engine
  • Service 的核心容器组件,一个 Service 只能有一个 Engine,是请求处理的总入口。
  • 核心职责:
    1. 接收所有 Connector 传递过来的请求,根据请求头中的 Host(域名)信息,将请求分发到对应的虚拟主机 Host 组件。
    2. 管理下属所有 Host 虚拟主机的生命周期,维护虚拟主机的映射关系。
    3. 处理默认路由,当请求的域名无法匹配到任何 Host 时,转发到defaultHost指定的默认虚拟主机。
    4. 支持 Valve 阀门组件,实现请求的全局拦截与处理(如日志、IP 过滤)。
5. Host
  • Engine 的子容器组件,一个 Engine 可包含多个 Host,每个 Host 对应一个虚拟主机(域名)。
  • 核心职责:
    1. 管理该域名下的所有 Web 应用 Context 组件,负责 Context 的部署、加载、卸载。
    2. 接收 Engine 分发的对应域名的请求,根据请求的上下文路径,转发到对应的 Context 组件。
    3. 支持自动部署(autoDeploy)、WAR 包自动解压(unpackWARs)、热部署等功能。
    4. 维护该虚拟主机的工作目录、资源路径,支持 Valve 阀门组件,实现该域名下的请求拦截。
6. Context
  • Host 的子容器组件,一个 Host 可包含多个 Context,每个 Context 对应一个独立的 Web 应用,是 Tomcat 最核心的 Servlet 运行上下文。
  • 核心职责:
    1. 代表一个 Web 应用,加载应用的WEB-INF/web.xml部署描述符,解析应用配置。
    2. 为每个 Web 应用创建独立的 WebappClassLoader 类加载器,实现应用间的类隔离。
    3. 管理下属所有 Wrapper 组件(Servlet 包装器),负责 Servlet 的加载、初始化、生命周期管理。
    4. 接收 Host 分发的请求,根据请求的 Servlet 路径,转发到对应的 Wrapper 组件处理。
    5. 管理应用的 Session 会话、静态资源、JNDI 资源、安全约束等所有应用级配置。
7. Wrapper
  • Context 的子容器组件,是 Tomcat 中最底层的容器,一个 Wrapper 对应一个 Servlet 实例。
  • 核心职责:
    1. 封装 Servlet 的所有信息,包括 Servlet 类名、初始化参数、负载信息、运行状态。
    2. 管理 Servlet 的完整生命周期,执行 Servlet 的init()service()destroy()方法。
    3. 负责 Servlet 的实例化、单例管理、线程安全控制,处理 Servlet 的请求调用。
    4. 维护 Servlet 的过滤器链,执行请求的过滤处理。

4.3 生命周期管理

Tomcat 的所有核心组件都实现了统一的Lifecycle 生命周期接口,实现了组件生命周期的统一管理,这是 Tomcat 模块化设计的核心基础。

1. 核心生命周期状态

Tomcat 组件的生命周期包含以下核心状态,按顺序流转:

  • NEW:新建状态,组件实例已创建,未初始化。
  • INITIALIZING/INITIALIZED:初始化中 / 初始化完成,执行init()方法,完成组件的配置加载、资源初始化。
  • STARTING_PREP/STARTING/STARTED:启动中 / 启动完成,执行start()方法,组件启动完成,可对外提供服务。
  • STOPPING_PREP/STOPPING/STOPPED:停止中 / 停止完成,执行stop()方法,组件停止服务,释放运行资源。
  • DESTROYING/DESTROYED:销毁中 / 销毁完成,执行destroy()方法,释放所有资源,组件生命周期结束。
  • FAILED:失败状态,组件在初始化、启动、停止过程中出现异常,进入失败状态。
2. 生命周期核心特性
  1. 层级联动 :组件的生命周期会向下传递,父组件的状态变化会触发所有子组件的对应状态变化。例如 Server 执行start()方法,会依次触发所有 Service→Engine→Host→Context→Wrapper 的start()方法,实现全组件的统一启动。
  2. 事件监听机制 :Lifecycle 接口支持事件监听机制,组件状态变化时会触发对应的生命周期事件,可通过实现LifecycleListener接口,自定义监听器,监听组件的状态变化,实现自定义扩展。
  3. 统一异常处理:所有组件的生命周期方法执行出现异常时,会统一进入 FAILED 状态,父组件可统一处理异常,保证容器的稳定性。
  4. 可复用性:组件完成停止与销毁后,可重新执行初始化与启动,实现组件的热重载与复用。

4.4 类加载机制

Tomcat 的类加载机制基于 Java 的双亲委派模型,但打破了默认的双亲委派规则,核心目的是实现 Web 应用之间的类隔离,以及 Web 应用与 Tomcat 容器的类隔离。

1. Java 默认双亲委派模型

Java 默认的类加载器层级为:Bootstrap ClassLoaderExtension ClassLoaderApplication ClassLoader。核心规则:类加载器收到类加载请求时,会先委托给父类加载器加载,只有父类加载器无法加载时,才会自己尝试加载,保证核心类的安全性与全局唯一性。

2. Tomcat 的类加载器层级

Tomcat 自定义了多个类加载器,形成了独立的类加载层级结构,如下:

plaintext

复制代码
┌─────────────────────────┐
│  Bootstrap ClassLoader  │  JVM根类加载器,加载Java核心类库
└───────────┬─────────────┘
            ↓
┌─────────────────────────┐
│  Extension ClassLoader  │  JVM扩展类加载器,加载jre/lib/ext类库
└───────────┬─────────────┘
            ↓
┌─────────────────────────┐
│   System ClassLoader    │  系统类加载器,加载CLASSPATH路径类库(Tomcat启动类)
└───────────┬─────────────┘
            ↓
┌─────────────────────────┐
│   Common ClassLoader    │  Tomcat公共类加载器,加载CATALINA_HOME/lib下的类库,容器与所有应用共享
└───────────┬─────────────┘
   ┌────────┴─────────┐
   ↓                  ↓
┌─────────────┐  ┌─────────────────────────┐
│ Catalina ClassLoader │  Shared ClassLoader │
│ 加载Tomcat容器自身类  │  加载所有Web应用共享的类库(默认关闭)
└─────────────┘  └───────────┬─────────────┘
                              ↓
                    ┌─────────────────────────┐
                    │ WebappClassLoader       │  每个Web应用对应一个独立的类加载器
                    └───────────┬─────────────┘
                              ↓
                    ┌─────────────────────────┐
                    │ JspClassLoader          │  每个JSP文件对应一个独立的类加载器
                    └─────────────────────────┘
3. Tomcat 类加载的核心规则(打破双亲委派)

Tomcat 的WebappClassLoader(Web 应用类加载器)打破了默认的双亲委派规则,核心加载逻辑如下:

  1. 先加载 JVM 核心类库(java.* 包),防止核心类被篡改,保证安全性。
  2. 尝试自己加载WEB-INF/classesWEB-INF/lib下的类,不先委托给父类加载器。
  3. 只有自己加载失败时,才会委托给父类加载器(Common/Shared ClassLoader)加载。
4. 核心设计目的与优势
  1. 应用间类隔离:每个 Web 应用有独立的 WebappClassLoader,不同应用之间的类库互不干扰。例如应用 A 使用 Spring 5.x,应用 B 使用 Spring 6.x,可在同一个 Tomcat 中正常运行,不会出现类版本冲突。
  2. 应用与容器隔离:Tomcat 容器自身的类库与 Web 应用的类库分开加载,应用的类库不会影响容器的运行,保证容器的稳定性。
  3. 热加载支持:每个应用的类加载器独立,应用热重载时,只需要销毁当前应用的 WebappClassLoader,重新创建新的类加载器,即可完成应用的重载,不影响其他应用与容器本身。
  4. 类共享支持:通过 Common/Shared ClassLoader,可实现多个应用共享通用类库,减少内存占用,例如将数据库驱动 jar 包放到 shared/lib 目录,所有应用可共享使用。

第五章:Web 应用部署

5.1 应用目录结构标准

Java Web 应用有严格的标准目录结构,Tomcat 完全遵循 Jakarta EE 规范,只有符合标准结构的 Web 应用才能被正常部署与加载。

标准 Web 应用目录结构如下:

plaintext

复制代码
Web应用根目录(如my-webapp)
├── 静态资源文件(HTML、CSS、JS、图片、字体等),可直接通过浏览器访问
├── WEB-INF
│   ├── web.xml               # 应用私有部署描述符,核心配置文件(可选,Servlet 3.0+支持注解替代)
│   ├── classes               # 编译后的Java类文件(.class),包括Servlet、Filter、Listener、业务类等
│   ├── lib                   # 应用依赖的第三方Jar包,如Spring、MyBatis、数据库驱动等
│   ├── tags                  # 自定义JSP标签库文件(可选)
│   └── tlds                  # 标签库描述符文件(可选)
└── META-INF
    ├── context.xml           # 应用私有上下文配置,覆盖全局context.xml(可选)
    ├── MANIFEST.MF           # 应用清单文件,定义应用的元数据、主类、依赖等(可选)
    └── services              # SPI服务配置文件(可选)

核心访问规则:

  • WEB-INFMETA-INF目录是受保护的,浏览器无法直接访问,只有 Tomcat 容器可以读取,保证应用的代码与配置安全。
  • 根目录下的静态资源文件,可直接通过浏览器访问,访问路径与文件路径一致。
  • classes目录下的类文件优先级高于lib目录下 Jar 包中的同名类,应用会优先加载classes中的类。

5.2 WAR 包部署与热部署

1. WAR 包概述

WAR(Web Application Archive)是 Java Web 应用的归档包格式,本质是 ZIP 格式的压缩包,将整个 Web 应用的所有文件打包为一个.war 后缀的文件,方便应用的传输、部署与版本管理。

2. 常规 WAR 包部署方式

Tomcat 支持多种 WAR 包部署方式,常用方式如下:

表格

部署方式 操作步骤 适用场景
自动部署 将 WAR 包直接放入CATALINA_HOME/webapps目录,Tomcat 开启autoDeploy=true时,会自动检测、解压 WAR 包,完成部署 开发测试环境、简单生产环境,最常用的部署方式
控制台部署 登录 Tomcat Manager App 管理界面,通过 "WAR file to deploy" 功能上传 WAR 包,完成在线部署 远程部署、无需登录服务器的场景,生产环境需限制访问权限
配置文件部署 server.xml的 Host 节点下添加 Context 节点,docBase指定 WAR 包的绝对路径,path指定访问路径,重启 Tomcat 生效 固定路径部署、WAR 包不在 webapps 目录的场景
上下文配置部署 conf/Catalina/[主机名]/目录下新建 XML 文件,文件名即为应用访问路径,文件中配置 Context 节点指定 WAR 包路径,无需重启 Tomcat 生产环境推荐,无需修改 server.xml,支持热部署,配置与应用分离
3. 热部署与热加载

热部署与热加载是 Tomcat 提供的应用动态更新能力,无需重启 Tomcat 实例,即可完成应用的更新与重载,两者有本质区别:

表格

特性 热加载(Reload) 热部署(Deploy)
核心原理 监控应用的 class 文件变化,变化后重新加载 Servlet,销毁并重建 WebappClassLoader 监控应用的 WAR 包 / 目录变化,变化后卸载整个 Context,重新部署整个 Web 应用
作用范围 仅重新加载变化的 class 文件与 Servlet,Session 不会丢失 重新部署整个应用,所有类重新加载,Session 会丢失
配置方式 Context 节点设置reloadable="true" Host 节点设置autoDeploy="true"unpackWARs="true"
性能影响 开销小,重载速度快 开销大,部署速度慢
适用场景 开发环境,频繁修改 Java 代码,快速调试 测试 / 生产环境,全量更新应用版本

生产环境注意:reloadable="true"会频繁触发类加载检查,严重影响性能,生产环境必须关闭;热部署建议仅在测试环境使用,生产环境更新应用建议先停止 Tomcat,替换应用后再启动,避免出现类加载异常与资源泄漏。

5.3 虚拟主机配置

虚拟主机指在同一个 Tomcat 实例上,运行多个域名的 Web 应用,每个域名对应一个独立的 Host 虚拟主机,实现多个网站共用一个 Tomcat 实例,节省服务器资源。

虚拟主机配置步骤
  1. 新增 Host 节点 :编辑conf/server.xml,在 Engine 节点下新增 Host 节点,配置域名与应用目录。
  2. 创建应用部署目录 :根据 Host 节点的appBase属性,创建对应的目录,存放该域名下的 Web 应用。
  3. 域名解析配置:将域名解析到 Tomcat 所在服务器的 IP 地址,本地测试可修改 hosts 文件。
  4. 重启 Tomcat:配置完成后重启 Tomcat,虚拟主机即可生效。
完整配置示例

需求:在同一个 Tomcat 上配置两个虚拟主机,分别对应www.app1.comwww.app2.com两个域名。

  1. server.xml 配置

xml

复制代码
<Engine name="Catalina" defaultHost="www.app1.com">
    <!-- 默认虚拟主机:www.app1.com -->
    <Host name="www.app1.com"  appBase="webapps-app1"
          unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="app1_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
    </Host>

    <!-- 新增虚拟主机:www.app2.com -->
    <Host name="www.app2.com"  appBase="webapps-app2"
          unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="app2_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
    </Host>
</Engine>
  1. 目录创建:在 Tomcat 根目录下创建webapps-app1webapps-app2两个目录,分别存放两个域名对应的 Web 应用。

  2. 本地测试:修改C:\Windows\System32\drivers\etc\hosts(Windows)或/etc/hosts(Linux/Mac)文件,添加如下配置:

    plaintext

    复制代码
    127.0.0.1 www.app1.com
    127.0.0.1 www.app2.com
  3. 部署应用:将app1.war放入webapps-app1目录,app2.war放入webapps-app2目录,重启 Tomcat,即可通过对应域名访问不同的应用。

核心注意点
  • Engine 节点的defaultHost必须配置为已存在的 Host 节点的 name,否则无法处理未知域名的请求。
  • 每个 Host 的appBase必须是独立的目录,不可共用,避免应用部署冲突。
  • 每个 Host 可配置独立的访问日志、Valve 阀门、自动部署策略,实现完全的配置隔离。

5.4 应用间隔离与共享

Tomcat 通过类加载机制与容器设计,天然支持 Web 应用间的隔离,同时提供了灵活的共享配置,满足不同的业务需求。

1. 应用间隔离

Tomcat 默认实现了应用间的三层隔离,保证应用之间互不干扰:

  1. 类加载隔离 :每个 Web 应用对应独立的 WebappClassLoader,应用的WEB-INF/classesWEB-INF/lib下的类仅对当前应用可见,不同应用之间的类库完全隔离,不会出现类版本冲突。
  2. 会话隔离:每个应用的 Session 是独立的,Session ID 与应用上下文路径绑定,不同应用之间的 Session 无法互相访问,保证会话数据安全。
  3. 资源隔离:每个应用的上下文是独立的,只能访问自身目录下的资源,无法直接访问其他应用的目录与资源,避免资源越权访问。
  4. 线程隔离:每个应用的请求处理线程是独立的,应用的异常不会直接影响其他应用的线程运行(极端情况除外,如 OOM)。
2. 应用间共享

Tomcat 提供了多种方式实现多个应用之间的资源、类库、配置共享,常用方式如下:

表格

共享类型 实现方式 适用场景 注意事项
类库共享 1. 将共享的 Jar 包放入CATALINA_HOME/lib目录,由 Common ClassLoader 加载,所有应用与容器共享2. 开启 Shared ClassLoader,将 Jar 包放入CATALINA_HOME/shared/lib目录,仅所有应用共享,容器不共享 多个应用共用的通用类库,如数据库驱动、工具类 Jar 包,避免重复加载,减少内存占用 共享类库必须保证版本兼容,所有应用使用同一个版本,更新 Jar 包需重启 Tomcat
配置共享 1. 全局配置:在conf/web.xmlconf/context.xml中配置全局参数,所有应用生效2. 虚拟主机共享:在 Host 节点中配置公共 Valve、资源,该主机下的所有应用共享 全局统一的配置,如全局会话超时、全局 MIME 类型、全局数据库连接池、全局 IP 过滤 应用私有配置会覆盖全局共享配置,优先级:应用私有配置 > 主机级配置 > 全局配置
静态资源共享 1. 配置全局 DefaultServlet,共享静态资源目录2. 通过 Context 的aliases属性配置资源别名,映射共享目录3. 前端 Nginx 做静态资源共享与分发 多个应用共用的静态资源,如图片、CSS、JS 通用组件,避免资源重复存储 注意资源访问权限控制,避免敏感资源泄露
数据共享 1. 通过数据库、Redis 等中间件实现数据共享2. 通过 JNDI 绑定全局共享对象,所有应用通过 JNDI 查找访问3. 通过跨域 Session 共享(需特殊配置) 多个应用之间的业务数据、用户信息共享 不建议通过 JVM 内存直接共享数据,会导致应用耦合,破坏隔离性

5.5 部署描述符配置

部署描述符即web.xml文件,是 Java Web 应用的核心配置文件,遵循 Jakarta EE Servlet 规范,用于定义 Web 应用的部署信息、组件配置、安全约束等,分为全局部署描述符conf/web.xml)和应用私有部署描述符WEB-INF/web.xml)。

1. 部署描述符的加载优先级
  • 应用私有web.xml会覆盖全局web.xml的同名配置,优先级更高。
  • Servlet 3.0 + 版本支持注解配置(如@WebServlet@WebFilter@WebListener),注解配置的优先级低于web.xml配置,web.xml可覆盖注解配置。
  • web.xmlmetadata-complete="true",则 Tomcat 会忽略所有注解配置,仅读取web.xml中的配置,加快应用启动速度。
2. 核心配置项详解

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
         version="6.0" metadata-complete="false">

    <!-- 1. 应用名称与描述 -->
    <display-name>MyWebApp</display-name>
    <description>我的第一个Java Web应用</description>

    <!-- 2. Servlet配置 -->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.test.HelloServlet</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup> <!-- 启动顺序,数字越小越先启动,负数则首次访问时初始化 -->
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

    <!-- 3. 过滤器配置 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern> <!-- 拦截所有请求 -->
    </filter-mapping>

    <!-- 4. 监听器配置 -->
    <listener>
        <listener-class>com.test.AppContextListener</listener-class>
    </listener>

    <!-- 5. 会话超时配置,单位分钟 -->
    <session-config>
        <session-timeout>30</session-timeout>
        <cookie-config>
            <http-only>true</http-only> <!-- 防止XSS攻击窃取Cookie -->
            <secure>false</secure> <!-- HTTPS环境下设置为true -->
        </cookie-config>
    </session-config>

    <!-- 6. 欢迎页配置,优先级从上到下 -->
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- 7. 错误页配置 -->
    <error-page>
        <error-code>404</error-code>
        <location>/404.html</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/500.html</location>
    </error-page>
    <error-page>
        <exception-type>java.lang.Exception</exception-type>
        <location>/error.html</location>
    </error-page>

    <!-- 8. MIME类型配置 -->
    <mime-mapping>
        <extension>pdf</extension>
        <mime-type>application/pdf</mime-type>
    </mime-mapping>

    <!-- 9. 安全约束配置,限制资源访问 -->
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>AdminResource</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee> <!-- 强制HTTPS访问 -->
        </user-data-constraint>
    </security-constraint>

    <!-- 10. 登录认证配置 -->
    <login-config>
        <auth-method>FORM</auth-method> <!-- 认证方式:BASIC/DIGEST/FORM/CLIENT-CERT -->
        <form-login-config>
            <form-login-page>/login.html</form-login-page>
            <form-error-page>/login-error.html</form-error-page>
        </form-login-config>
    </login-config>

    <!-- 11. 安全角色声明 -->
    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>

</web-app>

第六章:连接器与协议

6.1 HTTP/1.1 连接器配置

HTTP/1.1 连接器是 Tomcat 最核心的连接器,负责处理 HTTP 协议请求,默认使用 NIO 非阻塞 IO 模型,是 Tomcat 对外提供服务的核心入口,核心配置在server.xml的 Connector 节点。

1. 基础核心配置

xml

复制代码
<Connector port="8080" 
           protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="UTF-8"
           useBodyEncodingForURI="true"
           maxPostSize="10485760" />

核心属性说明:

表格

属性 作用 默认值 推荐配置
port 连接器监听的端口 8080 80(HTTP)、8080(测试)
protocol 协议与 IO 模型 HTTP/1.1 HTTP/1.1(默认对应 NIO)
connectionTimeout 连接超时时间,单位毫秒,客户端建立连接后未发送请求的超时时间 20000 生产环境 10000-30000
redirectPort 当请求需要 HTTPS 时,自动重定向的端口 8443 443(HTTPS)
URIEncoding URI 请求地址的编码格式 ISO-8859-1 UTF-8,解决中文乱码
useBodyEncodingForURI 是否使用请求体的编码格式处理 URI 参数 false true,统一编码
maxPostSize POST 请求体的最大大小,单位字节 2097152(2MB) 10485760(10MB),-1 为不限制
enableLookups 是否开启 DNS 反向解析,获取客户端主机名 false false,开启会严重影响性能
2. 高级性能配置

xml

复制代码
<Connector port="8080" 
           protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="UTF-8"
           maxThreads="200"
           minSpareThreads="20"
           maxConnections="10000"
           acceptCount="100"
           keepAliveTimeout="60000"
           maxKeepAliveRequests="100"
           compression="on"
           compressionMinSize="2048"
           compressibleMimeType="text/html,text/xml,text/plain,text/css,application/javascript,application/json" />

核心性能属性说明:

  • maxThreads:连接器线程池的最大线程数,处理请求的最大并发线程数,默认 200,根据服务器配置调整,CPU 密集型建议 100-200,IO 密集型建议 200-400。
  • minSpareThreads:线程池的最小空闲线程数,保证线程池始终有可用线程,默认 10,推荐 20-50。
  • maxConnections:Tomcat 最大可接受的并发连接数,NIO 模型默认 10000,根据服务器内存与并发量调整。
  • acceptCount:当所有线程都被占用时,等待队列的最大长度,默认 100,超过后会拒绝新的连接,生产环境不建议设置过大。
  • keepAliveTimeout:长连接的超时时间,单位毫秒,默认与 connectionTimeout 一致,HTTP 长连接保持时间,减少 TCP 握手开销。
  • maxKeepAliveRequests:一个长连接最多处理的请求数,默认 100,超过后关闭连接,-1 为不限制。
  • compression:是否开启 Gzip 压缩,on 为开启,off 为关闭,force 为强制压缩,开启后可大幅减少网络传输量,提升访问速度。
  • compressionMinSize:开启压缩的最小文件大小,单位字节,默认 2048,小于该值的文件不压缩。
  • compressibleMimeType:需要压缩的 MIME 类型,仅压缩文本类资源,图片、视频等二进制资源无需压缩。

6.2 AJP 连接器与 Web 服务器集成

AJP(Apache JServ Protocol)是一种面向二进制的 TCP 协议,专门用于 Tomcat 与前端 Web 服务器(Apache、Nginx)的通信,相比 HTTP 协议,AJP 协议的解析开销更小,性能更高,且能完整保留客户端的原始请求信息(如客户端 IP、端口、HTTPS 状态等)。

1. AJP 连接器核心配置

Tomcat 默认自带 AJP 连接器配置,默认端口 8009,高版本 Tomcat 默认开启密钥认证,防止未授权访问。

xml

复制代码
<Connector protocol="AJP/1.3"
           port="8009"
           redirectPort="8443"
           secretRequired="true"
           secret="AJP@Secret123456"
           maxThreads="200"
           connectionTimeout="20000"
           enableLookups="false" />

核心属性说明:

  • secretRequired:是否强制密钥认证,Tomcat 8.5.51+、9.0.31 + 版本默认 true,必须配置 secret,否则无法启动。
  • secret:密钥字符串,必须与前端 Web 服务器的 AJP 配置中的密钥一致,防止未授权的 AJP 连接。
  • 其他属性(maxThreads、connectionTimeout 等)与 HTTP 连接器一致。
2. 与 Web 服务器集成场景

AJP 连接器主要用于 Tomcat 与前端 Web 服务器的深度集成,核心应用场景如下:

  1. 动静分离:前端 Web 服务器处理静态资源请求,动态请求通过 AJP 协议转发给 Tomcat 处理,充分利用 Web 服务器的静态资源处理能力。
  2. 负载均衡:前端 Web 服务器作为负载均衡器,通过 AJP 协议将请求转发给后端多个 Tomcat 节点,实现集群负载均衡。
  3. HTTPS 卸载:前端 Web 服务器处理 HTTPS 加解密,将请求通过 AJP 协议转发给 Tomcat,减少 Tomcat 的性能开销,同时保留 HTTPS 状态信息。
  4. 安全防护:Tomcat 不直接对外暴露,仅通过前端 Web 服务器访问,Web 服务器可实现 WAF、IP 黑白名单、限流等安全防护,提升系统安全性。
3. 与 Nginx 集成配置示例

Nginx 从 1.9.11 版本开始支持 AJP 协议,需要加载ngx_http_ajp_module模块,核心配置如下:

  1. Nginx 配置

nginx

复制代码
http {
    upstream tomcat_cluster {
        server 127.0.0.1:8009;
        # 多个Tomcat节点可配置多个server,实现负载均衡
        # server 192.168.1.100:8009;
    }

    server {
        listen 80;
        server_name www.test.com;

        # 静态资源由Nginx处理
        location ~* \.(html|css|js|png|jpg|gif|ico)$ {
            root /usr/local/nginx/static;
            expires 7d;
        }

        # 动态请求通过AJP转发给Tomcat
        location / {
            ajp_pass tomcat_cluster;
            ajp_secret AJP@Secret123456; # 与Tomcat AJP配置的secret一致
            ajp_connect_timeout 10s;
            ajp_read_timeout 60s;
            ajp_send_timeout 60s;
        }
    }
}
  1. 注意事项:
    • 不使用 AJP 协议时,必须注释或删除 AJP 连接器配置,减少安全风险。
    • 生产环境必须配置 secret,禁止secretRequired="false",防止 AJP 协议漏洞攻击。
    • AJP 协议是 TCP 协议,仅用于内网服务器之间的通信,禁止将 AJP 端口对外网暴露。

6.3 NIO、NIO2、APR 连接器对比

Tomcat 的 HTTP/AJP 连接器支持三种 IO 模型,分别是 NIO、NIO2、APR,不同的 IO 模型在性能、并发能力、资源占用上有明显差异,适用于不同的业务场景。

1. 三种 IO 模型核心说明
  1. NIO(Non-Blocking IO,非阻塞 IO)

    • 基于 Java NIO 实现,是 Tomcat 8.5 + 版本的默认 IO 模型,采用 IO 多路复用 + 非阻塞 IO 的设计。
    • 核心原理:通过一个 Acceptor 线程接收客户端连接,将连接注册到 Selector 多路复用器,由少量的 Poller 线程监控连接的 IO 事件,当有可读 / 可写事件时,将请求交给线程池中的 Worker 线程处理。
    • 核心优势:线程模型高效,少量线程即可处理大量并发连接,线程开销小,并发能力强,内存占用低,稳定性好,无需额外依赖,跨平台兼容。
  2. NIO2(Asynchronous IO,异步 IO)

    • 基于 Java NIO2 实现,是 JDK 7 + 提供的异步 IO 模型,采用 Proactor 模式,完全异步非阻塞。
    • 核心原理:与 NIO 的 Reactor 模式不同,NIO2 直接向操作系统提交 IO 操作,操作系统完成 IO 操作后,主动通知 Tomcat 执行后续处理,无需线程轮询 IO 事件。
    • 核心优势:完全异步,高并发下 CPU 利用率更高,处理大量长连接、慢连接场景性能更优,支持异步 Servlet,减少线程阻塞。
    • 劣势:部分操作系统对异步 IO 的支持不完善,兼容性不如 NIO,实际生产环境性能提升不明显,使用较少。
  3. APR(Apache Portable Runtime,Apache 可移植运行时)

    • 基于 Apache APR 原生库实现,是 Tomcat 推荐的生产环境高性能 IO 模型,通过原生代码处理网络通信与文件操作,大幅提升性能。
    • 核心原理:APR 是 Apache 的跨平台原生库,封装了操作系统的底层 API,Tomcat 通过 JNI 调用 APR 库,直接使用操作系统的原生 IO 接口,绕过 JVM 的 IO 处理,减少 JVM 的开销,同时支持 OpenSSL 原生 HTTPS 加解密。
    • 核心优势:性能最强,接近 Apache HTTP Server 的性能,高并发下延迟更低,CPU 利用率更高,原生支持 OpenSSL,HTTPS 处理性能大幅提升,适合高并发、大流量的生产环境。
    • 劣势:需要额外安装 APR、APR-util、OpenSSL 原生库,安装配置复杂,跨平台兼容性差,不同操作系统需要单独编译安装。
2. 核心参数对比

表格

对比维度 NIO(默认) NIO2 APR
底层实现 Java NIO Reactor 模式 Java NIO2 Proactor 模式 Apache APR 原生库 + JNI
阻塞类型 非阻塞 IO 异步非阻塞 IO 原生 IO,支持非阻塞
并发能力 高,支持万级并发连接 极高,长连接场景更优 极高,大流量场景性能最优
性能表现 优秀,满足绝大多数场景 优秀,特定场景优于 NIO 极致,整体性能优于 NIO/NIO2
资源占用 低,线程开销小 低,线程开销最小 中等,原生库开销,CPU 利用率更高
兼容性 极好,跨平台,无额外依赖 良好,JDK 7 + 支持 一般,需安装原生库,不同系统配置不同
配置难度 简单,开箱即用 简单,仅需修改 protocol 复杂,需安装依赖库,配置参数多
HTTPS 性能 良好,Java JSSE 实现 良好,同 NIO 优秀,原生 OpenSSL 实现,性能提升 50%+
适用场景 绝大多数生产环境、中小项目、微服务 长连接、异步 Servlet、慢连接场景 高并发大流量项目、HTTPS 站点、大型生产环境
3. 配置切换方式

修改 Connector 节点的protocol属性,即可切换 IO 模型,修改后重启 Tomcat 生效:

  • NIO 模型:protocol="org.apache.coyote.http11.Http11NioProtocol"(简写HTTP/1.1,默认)
  • NIO2 模型:protocol="org.apache.coyote.http11.Http11Nio2Protocol"
  • APR 模型:protocol="org.apache.coyote.http11.Http11AprProtocol"

6.4 SSL/TLS 配置与 HTTPS 启用

Tomcat 支持 SSL/TLS 协议,可配置 HTTPS 连接器,实现数据加密传输,保证通信安全,支持 Java JSSE 与 APR OpenSSL 两种实现方式。

1. 前置准备:SSL 证书

启用 HTTPS 必须先获取 SSL 证书,证书分为两种:

  • 自签名证书:通过 JDK 的 keytool 工具生成,仅用于测试环境,浏览器会提示不安全。
  • 权威 CA 证书:由阿里云、腾讯云、Let's Encrypt 等权威机构颁发,浏览器信任,用于生产环境,支持单域名、多域名、泛域名证书。
2. 测试环境:自签名证书生成

使用 JDK 自带的 keytool 工具生成自签名证书,执行以下命令:

bash

运行

复制代码
keytool -genkey -alias tomcat-https -keyalg RSA -keysize 2048 -validity 365 -keystore tomcat.keystore
  • -alias:证书别名,自定义
  • -keyalg:加密算法,固定 RSA
  • -keysize:密钥长度,推荐 2048
  • -validity:证书有效期,单位天
  • -keystore:生成的密钥库文件名称

执行命令后,按提示设置密钥库密码、证书信息,完成后会生成tomcat.keystore密钥库文件,将文件放入 Tomcat 的conf目录。

3. HTTPS 连接器核心配置

编辑conf/server.xml,新增 HTTPS 连接器配置,默认端口 8443,生产环境建议改为 443。

配置 1:JSSE 实现(NIO 模型,无需额外依赖,推荐测试 / 简单生产环境)

xml

复制代码
<Connector port="8443" 
           protocol="HTTP/1.1"
           maxThreads="200"
           SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/tomcat.keystore"
                     certificateKeystorePassword="123456"
                     certificateKeyAlias="tomcat-https"
                     type="RSA" />
        <!-- 安全配置,禁用不安全的协议与加密套件 -->
        <Protocols>TLSv1.2,TLSv1.3</Protocols>
        <ciphers>TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</ciphers>
    </SSLHostConfig>
</Connector>
配置 2:APR 实现(APR 模型,生产环境高性能推荐)

需提前安装 APR 与 OpenSSL 库,配置如下:

xml

复制代码
<Connector port="443" 
           protocol="org.apache.coyote.http11.Http11AprProtocol"
           maxThreads="200"
           SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeyFile="conf/private.key"
                     certificateFile="conf/certificate.crt"
                     certificateChainFile="conf/ca-bundle.crt"
                     type="RSA" />
        <Protocols>TLSv1.2,TLSv1.3</Protocols>
        <SSLHonorCipherOrder>on</SSLHonorCipherOrder>
    </SSLHostConfig>
</Connector>
4. 核心配置说明
  • SSLEnabled="true":开启 SSL/TLS 支持,启用 HTTPS。
  • certificateKeystoreFile:密钥库文件路径,相对路径相对于 CATALINA_HOME。
  • certificateKeystorePassword:密钥库密码,与生成证书时设置的密码一致。
  • Protocols:支持的 SSL/TLS 协议版本,必须禁用 SSLv3、TLSv1.0、TLSv1.1,仅保留 TLSv1.2、TLSv1.3,防止安全漏洞。
  • ciphers:支持的加密套件,禁用不安全的加密套件,仅保留高强度加密套件。
  • redirectPort:HTTP 连接器的 redirectPort 必须配置为 HTTPS 连接器的端口,当请求需要安全传输时,自动重定向到 HTTPS 端口。
5. HTTP 强制跳转 HTTPS

配置完成 HTTPS 后,可通过配置实现 HTTP 请求自动跳转为 HTTPS,编辑conf/web.xml,在文件末尾添加如下配置:

xml

复制代码
<security-constraint>
    <web-resource-collection>
        <web-resource-name>HTTPS-Force</web-resource-name>
        <url-pattern>/*</url-pattern> <!-- 拦截所有请求 -->
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee> <!-- 强制机密传输,自动跳转HTTPS -->
    </user-data-constraint>
</security-constraint>

配置完成后,访问http://localhost:8080会自动跳转到https://localhost:8443

6. 生产环境最佳实践
  1. 使用权威 CA 机构颁发的证书,禁止使用自签名证书。
  2. 禁用不安全的 SSL/TLS 协议版本,仅支持 TLSv1.2、TLSv1.3。
  3. 禁用弱加密套件,仅使用高强度的加密套件,开启 HSTS,防止降级攻击。
  4. HTTPS 端口使用 443,HTTP 端口使用 80,简化用户访问。
  5. 高并发场景使用 APR+OpenSSL 实现,提升 HTTPS 处理性能。
  6. 证书到期前提前更新,避免证书过期导致网站无法访问。
  7. 生产环境建议使用 Nginx 作为 HTTPS 卸载入口,Tomcat 仅处理内网 HTTP 请求,简化配置,提升性能。

第七章:性能调优

Tomcat 性能调优是一个系统性的工作,核心围绕 JVM、连接器、应用配置、资源优化四个维度,目标是提升系统的并发能力、降低响应延迟、提高稳定性,避免出现性能瓶颈。

7.1 JVM 参数优化

Tomcat 运行在 JVM 之上,JVM 的性能直接决定了 Tomcat 的整体性能,JVM 优化的核心是内存分配、GC 算法选择、垃圾回收优化,减少 GC 停顿时间,避免内存溢出。

1. JVM 参数配置方式

Tomcat 的 JVM 参数通过CATALINA_OPTS环境变量配置,推荐在bin目录下新建setenv.sh(Linux/Mac)/setenv.bat(Windows)文件,Tomcat 启动时会自动读取该文件的配置,无需修改原有脚本。

Linux/Mac 配置示例(bin/setenv.sh):

bash

运行

复制代码
#!/bin/bash
# JVM内存配置
export CATALINA_OPTS="$CATALINA_OPTS -Xms2g -Xmx2g"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:NewRatio=2 -XX:SurvivorRatio=8"
# GC算法配置
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseG1GC"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxGCPauseMillis=200"
# 优化配置
export CATALINA_OPTS="$CATALINA_OPTS -XX:+DisableExplicitGC"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
export CATALINA_OPTS="$CATALINA_OPTS -XX:HeapDumpPath=$CATALINA_HOME/logs/heapdump.hprof"
export CATALINA_OPTS="$CATALINA_OPTS -Djava.awt.headless=true"

Windows 配置示例(bin/setenv.bat):

bat

复制代码
set CATALINA_OPTS=%CATALINA_OPTS% -Xms2g -Xmx2g
set CATALINA_OPTS=%CATALINA_OPTS% -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
set CATALINA_OPTS=%CATALINA_OPTS% -XX:+UseG1GC
set CATALINA_OPTS=%CATALINA_OPTS% -XX:MaxGCPauseMillis=200
set CATALINA_OPTS=%CATALINA_OPTS% -XX:+DisableExplicitGC
set CATALINA_OPTS=%CATALINA_OPTS% -XX:+HeapDumpOnOutOfMemoryError
set CATALINA_OPTS=%CATALINA_OPTS% -XX:HeapDumpPath=%CATALINA_HOME%/logs/heapdump.hprof
set CATALINA_OPTS=%CATALINA_OPTS% -Djava.awt.headless=true
2. 核心 JVM 参数详解
(1)内存分配参数

表格

参数 作用 调优建议
-Xms 堆内存初始值 生产环境建议与 - Xmx 设置为相同值,避免堆内存动态扩容带来的性能开销
-Xmx 堆内存最大值 不可超过服务器物理内存的 70%,需预留内存给操作系统、元空间、直接内存、其他进程;4 核 8G 服务器推荐 2-4g,8 核 16G 服务器推荐 4-8g
-XX:NewRatio 老年代与新生代的比例 默认 2,即老年代占 2/3 堆内存,新生代占 1/3;IO 密集型应用可调整为 1,增大新生代空间,减少 Minor GC 频率
-XX:SurvivorRatio Eden 区与 Survivor 区的比例 默认 8,即 Eden:From Survivor:To Survivor=8:1:1,常规应用无需调整
-XX:MetaspaceSize 元空间初始值 推荐 256m,避免元空间动态扩容触发 Full GC
-XX:MaxMetaspaceSize 元空间最大值 推荐 512m-1g,防止元空间内存溢出
(2)GC 算法配置

JDK 8 + 推荐使用 G1GC,JDK 17 + 可使用 ZGC/ShenandoahGC,低延迟场景优先选择 ZGC。

表格

GC 算法 适用场景 核心参数
G1GC 绝大多数生产环境,堆内存 4g 以上,平衡吞吐量与延迟 -XX:+UseG1GC、-XX:MaxGCPauseMillis=200(最大 GC 停顿时间,默认 200ms)
ZGC 大堆内存、低延迟要求场景,JDK 11 + 支持 -XX:+UseZGC、-XX:ZCollectionInterval=30
Parallel GC 吞吐量优先场景,后台任务、批处理应用 -XX:+UseParallelGC、-XX:MaxGCPauseMillis=200
(3)优化与故障排查参数
  • -XX:+DisableExplicitGC:禁用 System.gc () 手动触发 Full GC,防止应用代码频繁触发 Full GC 导致性能下降。
  • -XX:+HeapDumpOnOutOfMemoryError:发生 OOM 时自动生成堆转储文件,用于故障排查。
  • -XX:HeapDumpPath:堆转储文件的保存路径,建议设置到 Tomcat 日志目录。
  • -Djava.awt.headless=true:开启无头模式,解决 Linux 环境下图片处理、验证码生成的异常问题。
3. 最佳实践
  1. 堆内存 Xms 与 Xmx 必须设置为相同值,避免堆内存动态调整。
  2. 禁止将 Xmx 设置过大,超过服务器物理内存的 70%,避免出现内存交换(Swap),严重影响性能。
  3. 优先使用 G1GC,低延迟场景使用 ZGC,不推荐使用 CMS GC(JDK 9 + 已废弃)。
  4. 必须配置 OOM 堆转储参数,方便内存溢出问题排查。
  5. 定期监控 GC 日志,分析 GC 频率与停顿时间,针对性调整内存分配。

7.2 连接器参数调优

连接器是 Tomcat 接收请求的入口,连接器的参数调优直接决定了 Tomcat 的并发处理能力,核心围绕连接数、线程池、超时、压缩四个维度优化。

1. 最大连接数调优

Tomcat 的连接数控制有三个核心参数,三者配合实现并发连接的控制,避免连接数打满导致服务不可用。

表格

参数 作用 调优建议
acceptCount 等待队列长度,当所有处理线程都被占用时,新的连接会进入等待队列,超过该值会拒绝连接 默认 100,生产环境建议 100-200,不可设置过大,否则会导致请求等待时间过长
maxConnections Tomcat 最大可接受的并发连接数,超过该值的连接会被阻塞,等待队列有空间后再处理 NIO 模型默认 10000,4 核 8G 服务器推荐 8000-10000,8 核 16G 服务器推荐 10000-20000
maxThreads 处理请求的最大线程数,线程池的上限,决定了 Tomcat 同时处理请求的最大并发数 默认 200,CPU 密集型应用推荐 100-200,IO 密集型应用推荐 200-400,不可设置过大,否则会导致线程上下文切换开销过大,性能下降

核心关系:acceptCount是排队的人数,maxConnections是大厅最多容纳的人数,maxThreads是处理业务的窗口数量。

2. 线程池配置优化

Tomcat 连接器使用自带的线程池处理请求,核心参数如下:

  • maxThreads:最大线程数,核心参数,根据业务类型调整,常规 Web 应用推荐 200-400,超过 800 后性能会明显下降。
  • minSpareThreads:最小空闲线程数,默认 10,推荐 20-50,保证始终有可用线程处理新的请求,减少线程创建开销。
  • maxIdleTime:空闲线程的存活时间,单位毫秒,默认 60000,空闲超过该时间的线程会被销毁,保留 minSpareThreads 个线程。

进阶优化:可在 server.xml 中配置全局共享线程池,多个连接器共用同一个线程池,实现线程资源的统一管理,配置如下:

xml

复制代码
<!-- 全局线程池配置,Service节点下,Connector节点前 -->
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
          maxThreads="300" minSpareThreads="30" maxIdleTime="60000" />
<!-- 连接器绑定线程池 -->
<Connector port="8080" protocol="HTTP/1.1"
           executor="tomcatThreadPool"
           connectionTimeout="20000"
           redirectPort="8443" />
3. 超时设置优化

超时设置的核心目的是释放无效连接,减少无效资源占用,避免大量空闲连接占用连接数,导致正常请求无法处理。

表格

参数 作用 调优建议
connectionTimeout 连接建立后,客户端未发送请求的超时时间,单位毫秒 默认 20000,生产环境推荐 5000-10000,高并发场景可设置为 3000
keepAliveTimeout 长连接的空闲超时时间,单位毫秒 默认与 connectionTimeout 一致,生产环境推荐 30000-60000,高并发短连接场景可设置为 5000
maxKeepAliveRequests 一个长连接最多处理的请求数 默认 100,高并发场景推荐 100-300,静态资源多的场景可设置为 1000
asyncTimeout 异步 Servlet 的超时时间,单位毫秒 默认 30000,根据业务场景调整
4. 其他核心优化参数
  • compression="on":开启 Gzip 压缩,压缩文本类资源,减少网络传输量,提升响应速度,同时配置compressionMinSize="2048"compressibleMimeType指定压缩类型。
  • enableLookups="false":关闭 DNS 反向解析,默认 false,必须保持关闭,否则每次请求都会进行 DNS 解析,严重影响性能。
  • maxPostSize="10485760":限制 POST 请求体的最大大小,默认 2MB,根据业务需求调整,避免大请求体占用过多资源。
  • URIEncoding="UTF-8":统一 URI 编码为 UTF-8,避免中文乱码,同时设置useBodyEncodingForURI="true"

7.3 禁用不必要的功能

Tomcat 默认开启了很多开发测试用的功能,生产环境禁用这些功能,可减少资源占用,提升性能,同时降低安全风险。

  1. 禁用默认 Web 应用 Tomcat 默认的 webapps 目录下包含docsexamplesmanagerhost-managerROOT自带应用,生产环境无需使用,直接删除,减少启动加载时间,降低安全风险。

  2. 禁用未使用的连接器不使用 AJP 协议时,直接注释或删除 server.xml 中的 AJP 连接器配置,减少端口监听与资源占用。

  3. 关闭热部署与热加载 生产环境设置 Host 节点的autoDeploy="false",Context 节点的reloadable="false",关闭热部署与热加载,避免频繁的类加载检查与应用重载,提升性能,同时避免类加载内存泄漏。

  4. 关闭 JSP 开发模式 编辑全局 web.xml,找到 JspServlet,设置development=false,关闭 JSP 开发模式,生产环境无需实时检查 JSP 文件变化,减少 JSP 编译检查开销,提升 JSP 访问性能。

    xml

    复制代码
    <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>development</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>genStringAsCharArray</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>
  5. 禁用不必要的阀门与监听器注释掉 server.xml 中未使用的 Valve 阀门与 LifecycleListener 监听器,减少请求处理的拦截开销。

  6. 禁用 WebSocket 支持应用不使用 WebSocket 时,禁用 WebSocket 功能,移除相关的 Jar 包与配置,减少资源占用。

7.4 静态资源缓存优化

Tomcat 的 DefaultServlet 负责处理静态资源请求,通过优化静态资源缓存,可减少磁盘 IO,提升静态资源的访问速度,降低服务器压力。

1. DefaultServlet 缓存配置

编辑全局 web.xml,找到 DefaultServlet,调整缓存相关参数:

xml

复制代码
<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <!-- 开启静态资源缓存 -->
    <init-param>
        <param-name>cachingAllowed</param-name>
        <param-value>true</param-value>
    </init-param>
    <!-- 缓存最大大小,单位KB,默认10240KB,生产环境推荐102400KB(100MB) -->
    <init-param>
        <param-name>cacheMaxSize</param-name>
        <param-value>102400</param-value>
    </init-param>
    <!-- 单个缓存文件的最大大小,单位KB,默认512KB -->
    <init-param>
        <param-name>cacheObjectMaxSize</param-name>
        <param-value>2048</param-value>
    </init-param>
    <!-- 缓存TTL,单位秒,默认5秒,生产环境推荐60秒 -->
    <init-param>
        <param-name>cacheTTL</param-name>
        <param-value>60</param-value>
    </init-param>
    <!-- 关闭目录浏览,生产环境必须关闭,提升安全 -->
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
2. 浏览器缓存优化(ExpiresFilter)

通过 Tomcat 自带的 ExpiresFilter 过滤器,设置静态资源的浏览器缓存过期时间,减少重复请求,降低服务器压力。

编辑全局 web.xml,添加 ExpiresFilter 配置:

xml

复制代码
<filter>
    <filter-name>ExpiresFilter</filter-name>
    <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
    <init-param>
        <param-name>ExpiresByType text/html</param-name>
        <param-value>access plus 1 hour</param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType text/css</param-name>
        <param-value>access plus 7 days</param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType application/javascript</param-name>
        <param-value>access plus 7 days</param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType image/png</param-name>
        <param-value>access plus 30 days</param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType image/jpg</param-name>
        <param-value>access plus 30 days</param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType image/gif</param-name>
        <param-value>access plus 30 days</param-value>
    </init-param>
    <init-param>
        <param-name>ExpiresByType image/ico</param-name>
        <param-value>access plus 30 days</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

最佳实践:生产环境推荐使用 Nginx 处理静态资源,实现动静分离,Nginx 的静态资源处理性能远高于 Tomcat,同时可更灵活的配置缓存、压缩、CDN 回源等。

7.5 压测工具与性能监控

性能调优必须基于数据,通过压测工具模拟真实并发场景,获取性能指标,通过监控工具定位性能瓶颈,针对性优化,避免盲目调优。

1. 常用压测工具

表格

工具 特点 适用场景 核心用法
ab(Apache Bench) Apache 自带,轻量简单,开箱即用,单线程,支持 HTTP/HTTPS 快速压测、简单并发场景、接口性能测试 ab -n 10000 -c 200 http://localhost:8080/,-n 总请求数,-c 并发数
wrk 高性能压测工具,多线程、异步 IO,支持 Lua 脚本,压测性能远高于 ab 高并发压测、复杂场景、生产环境性能验证 wrk -t 4 -c 200 -d 30s http://localhost:8080/,-t 线程数,-c 并发数,-d 压测时长
JMeter Apache 开源,图形化界面,功能强大,支持多种协议,可编写复杂压测场景 全链路压测、复杂业务场景、分布式压测、接口自动化测试 图形化配置线程组、请求、断言、监听器,生成压测报告
Gatling 基于 Scala,高性能,异步 IO,支持 DSL 脚本,生成精美 HTML 报告 高并发压测、持续集成压测、生产环境性能基准测试 编写 Scala 压测脚本,执行压测,生成报告

压测核心指标:

  • QPS/TPS:每秒处理的请求数 / 事务数,核心性能指标,越高越好。
  • 响应时间:平均响应时间、95 分位响应时间、99 分位响应时间,越低越好。
  • 并发数:系统可同时处理的并发请求数,越高越好。
  • 错误率:请求失败的比例,生产环境必须低于 0.01%。
  • CPU / 内存使用率:压测过程中服务器的 CPU、内存、IO、网络资源占用。
2. 性能监控工具
(1)JVM 监控工具
  • jps :JDK 自带,查看 Java 进程 PID,jps -l
  • jstat :JDK 自带,实时监控 JVM GC、内存使用情况,jstat -gc [PID] 1000 10,每秒输出一次,共 10 次。
  • jmap :JDK 自带,生成堆转储文件,查看堆内存使用情况,jmap -dump:format=b,file=heapdump.hprof [PID]
  • JConsole/VisualVM:JDK 自带图形化监控工具,实时监控 JVM 内存、线程、GC、CPU 使用率,支持堆转储文件分析,定位内存泄漏。
  • MAT:Eclipse Memory Analyzer,专业的堆内存分析工具,定位内存泄漏、大对象、类加载器泄漏问题。
(2)Tomcat 自带监控工具
  • Manager App:Tomcat 自带的管理界面,可查看 Tomcat 运行状态、线程池、连接器、应用部署状态、Session 信息,支持 JVM 内存监控。
  • Host Manager:虚拟主机管理界面,查看与管理虚拟主机配置。
(3)生产环境监控工具
  • Prometheus + Grafana:主流的监控方案,通过 Tomcat Exporter 采集 Tomcat 与 JVM 指标,Prometheus 存储指标数据,Grafana 实现可视化监控面板,配置告警规则。
  • ELK Stack:Elasticsearch+Logstash+Kibana,实现 Tomcat 日志的采集、存储、分析、可视化,快速定位异常请求、错误日志。
  • APM 工具:SkyWalking、Pinpoint、Cat,分布式链路追踪工具,全链路监控请求的执行过程,定位慢接口、SQL 慢查询、异常调用,适合微服务架构。
3. 性能调优流程
  1. 基准测试:使用压测工具对系统进行压测,获取基准性能指标(QPS、响应时间、CPU / 内存使用率)。
  2. 瓶颈定位:通过监控工具,定位性能瓶颈,是 JVM GC 频繁、线程池满、连接数打满、数据库慢查询、还是应用代码问题。
  3. 针对性优化:针对瓶颈点,制定优化方案,调整对应参数,优化代码。
  4. 优化验证:再次进行压测,对比优化前后的性能指标,验证优化效果。
  5. 持续迭代:重复以上步骤,直到性能达到预期目标,同时建立常态化的性能监控机制。

第八章:安全管理

Tomcat 的安全管理是生产环境部署的核心环节,核心围绕认证授权、数据加密、漏洞防范、权限最小化四个维度,防止未授权访问、数据泄露、恶意攻击,保证系统的安全稳定运行。

8.1 用户认证与授权

Tomcat 的认证与授权基于Realm(安全域) 实现,Realm 是 Tomcat 的用户认证组件,负责验证用户名密码、查询用户对应的角色,实现用户的认证与授权,Tomcat 提供了多种 Realm 实现,适用于不同的业务场景。

1. 核心认证流程
  1. 客户端发起受保护资源的请求。
  2. Tomcat 的安全拦截器拦截请求,判断用户是否已认证。
  3. 未认证用户,根据配置的认证方式,弹出登录框或跳转到登录页面。
  4. 用户提交用户名密码,Tomcat 将凭证传递给 Realm 进行认证。
  5. Realm 验证用户名密码是否正确,查询用户对应的角色。
  6. 认证通过后,判断用户角色是否有权限访问该资源,有权限则允许访问,无权限则返回 403 拒绝访问。
2. 内存域(MemoryRealm)

MemoryRealm 是 Tomcat 默认的 Realm 实现,从conf/tomcat-users.xml配置文件中读取用户、角色信息,将数据加载到内存中,实现认证授权。

  • 核心特点:配置简单、开箱即用、无需额外依赖,读取速度快。
  • 适用场景:开发测试环境、小型应用、用户数量固定且极少变化的场景。
  • 配置方式:默认开启,无需额外配置,直接编辑tomcat-users.xml配置用户与角色即可,详细配置见 3.5 节。
  • 劣势:用户信息硬编码在配置文件中,修改用户需要重启 Tomcat,不支持动态修改,不适合用户量大的场景。
3. JDBC 域(JDBCRealm)

JDBCRealm 通过 JDBC 连接数据库,从数据库表中读取用户、角色信息,实现认证授权,支持用户信息的动态管理,无需重启 Tomcat。

  • 核心特点:用户信息存储在数据库中,支持动态增删改查,可与业务系统的用户体系集成,灵活度高。

  • 适用场景:生产环境、中大型应用、用户数量多、需要动态管理用户的场景。

  • 前置准备:

    1. 数据库中创建用户表、角色表,表结构示例: sql

      复制代码
      -- 用户表
      CREATE TABLE users (
          username VARCHAR(50) NOT NULL PRIMARY KEY,
          password VARCHAR(100) NOT NULL,
          enabled TINYINT NOT NULL DEFAULT 1
      );
      -- 角色表
      CREATE TABLE user_roles (
          username VARCHAR(50) NOT NULL,
          role_name VARCHAR(50) NOT NULL,
          PRIMARY KEY (username, role_name)
      );
    2. 向表中插入用户数据,密码建议使用 MD5/SHA-256 加密。

    3. 将数据库驱动 Jar 包放入 Tomcat 的lib目录。

  • 配置方式:编辑conf/server.xml,在 Engine 节点下添加 JDBCRealm 配置:

    xml

    复制代码
    <Realm className="org.apache.catalina.realm.JDBCRealm"
           driverName="com.mysql.cj.jdbc.Driver"
           connectionURL="jdbc:mysql://localhost:3306/tomcat_db?useSSL=false&amp;serverTimezone=UTC"
           connectionName="root"
           connectionPassword="123456"
           userTable="users"
           userNameCol="username"
           userCredCol="password"
           userRoleTable="user_roles"
           roleNameCol="role_name"
           <!-- 密码加密配置 -->
           digest="SHA-256"
           digestEncoding="UTF-8" />
  • 核心属性说明:

    • driverName:数据库驱动类名。
    • connectionURL/connectionName/connectionPassword:数据库连接地址、用户名、密码。
    • userTable:用户表名。
    • userNameCol:用户名字段名。
    • userCredCol:密码字段名。
    • userRoleTable:用户角色关联表名。
    • roleNameCol:角色名字段名。
    • digest:密码加密算法,支持 MD5、SHA-256、SHA-512 等,禁止明文存储密码。
4. JNDI 域(JNDIRealm)

JNDIRealm 通过 JNDI 连接 LDAP 目录服务器(如 Active Directory、OpenLDAP),从 LDAP 服务器中读取用户、角色信息,实现认证授权。

  • 核心特点:与企业级 LDAP 用户体系集成,统一用户管理,适合企业内部系统、单点登录场景。

  • 适用场景:大型企业应用、企业内部系统、需要与 LDAP/AD 集成的场景。

  • 配置方式:编辑conf/server.xml,在 Engine 节点下添加 JNDIRealm 配置:

    xml

    复制代码
    <Realm className="org.apache.catalina.realm.JNDIRealm"
           connectionURL="ldap://localhost:389"
           alternateURL="ldap://localhost:389"
           connectionName="cn=admin,dc=test,dc=com"
           connectionPassword="123456"
           userPattern="uid={0},ou=users,dc=test,dc=com"
           userRoleName="memberOf"
           roleBase="ou=roles,dc=test,dc=com"
           roleName="cn"
           roleSearch="(member={0})"
           roleSubtree="true" />

8.2 角色与权限管理

Tomcat 的权限管理基于角色实现,采用 RBAC(基于角色的访问控制)模型,用户绑定角色,角色绑定权限,实现用户与权限的解耦,灵活的权限管理。

1. 核心权限模型
  • 用户(User):访问系统的主体,对应一个账号。
  • 角色(Role):权限的集合,代表一类操作权限,如管理员、普通用户、运维人员。
  • 权限(Permission):对资源的访问权限,如访问管理界面、访问 /admin 路径、修改配置等。
  • 核心关系:一个用户可绑定多个角色,一个角色可被多个用户绑定;一个角色可拥有多个权限,一个权限可分配给多个角色。
2. 内置角色与权限

Tomcat 内置了管理界面的专用角色,详细说明见 3.5 节,核心分为 manager 系列(应用管理)和 admin 系列(主机管理),每个角色对应不同的操作权限,实现权限的细粒度控制。

3. 自定义资源权限控制

通过web.xml中的security-constraint配置,可实现对应用中特定资源的访问权限控制,限制只有指定角色的用户才能访问。

完整配置示例:

xml

复制代码
<!-- 安全约束:限制/admin路径下的资源,只有admin角色可访问 -->
<security-constraint>
    <!-- 受保护的资源集合 -->
    <web-resource-collection>
        <web-resource-name>AdminResource</web-resource-name>
        <url-pattern>/admin/*</url-pattern> <!-- 受保护的路径 -->
        <http-method>GET</http-method> <!-- 受保护的请求方法 -->
        <http-method>POST</http-method>
    </web-resource-collection>
    <!-- 授权约束:允许访问的角色 -->
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>super-admin</role-name>
    </auth-constraint>
    <!-- 数据传输约束:CONFIDENTIAL强制HTTPS访问,NONE无限制 -->
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

<!-- 登录认证配置 -->
<login-config>
    <!-- 认证方式:BASIC(基础弹窗认证)、DIGEST(摘要认证)、FORM(表单登录)、CLIENT-CERT(客户端证书认证) -->
    <auth-method>FORM</auth-method>
    <realm-name>MyWebAppRealm</realm-name>
    <!-- 表单登录配置,仅auth-method=FORM时生效 -->
    <form-login-config>
        <form-login-page>/login.html</form-login-page>
        <form-error-page>/login-error.html</form-error-page>
    </form-login-config>
</login-config>

<!-- 声明安全角色,必须与上面授权约束中的角色一致 -->
<security-role>
    <role-name>admin</role-name>
</security-role>
<security-role>
    <role-name>super-admin</role-name>
</security-role>
4. 权限管理最佳实践
  1. 最小权限原则:给用户分配最小的必要权限,禁止给普通用户分配管理角色,禁止使用管理员账号运行应用。
  2. 角色细分:将权限细分为多个角色,如只读角色、运维角色、管理角色,避免一个角色拥有所有权限。
  3. 禁止明文存储密码:所有密码必须加密存储,推荐使用 SHA-256 + 盐值加密,禁止使用 MD5 等弱加密算法。
  4. 定期权限审计:定期审计用户与角色配置,清理无效用户、过期权限,避免权限泄露。
  5. 强制 HTTPS 访问:所有受保护的资源,必须强制使用 HTTPS 传输,防止账号密码被网络嗅探窃取。

8.3 SSL 证书配置

SSL 证书配置与 HTTPS 启用,是 Tomcat 安全管理的核心环节,通过 HTTPS 实现客户端与服务器之间的数据加密传输,防止数据被窃听、篡改、伪造,详细配置见 6.4 节,本节补充安全最佳实践。

1. 证书安全配置
  1. 使用权威 CA 证书:生产环境必须使用全球信任的权威 CA 机构颁发的证书,禁止使用自签名证书、私有 CA 证书,避免浏览器不信任。
  2. 证书类型选择:优先选择 EV/OV 证书,安全性更高;泛域名证书适合多个子域名场景,减少证书管理成本。
  3. 证书密钥安全:证书私钥必须使用 2048 位及以上的 RSA 密钥,或 ECC 椭圆曲线密钥,禁止使用 1024 位及以下的弱密钥;私钥文件必须严格保密,设置最小权限,禁止对外泄露。
  4. 证书到期管理:建立证书到期提醒机制,提前 1-3 个月更新证书,避免证书过期导致网站无法访问。
2. SSL/TLS 安全配置
  1. 禁用不安全的协议版本:必须禁用 SSLv2、SSLv3、TLSv1.0、TLSv1.1,仅支持 TLSv1.2、TLSv1.3,防止 POODLE、BEAST 等漏洞攻击。

  2. 禁用弱加密套件:禁用匿名、弱加密、出口级加密套件,仅使用高强度的 AEAD 加密套件,优先使用前向安全(FS)的加密套件。

  3. 开启 HSTS :配置 HTTP 严格传输安全(HSTS),强制浏览器使用 HTTPS 访问,防止 SSL 降级攻击、中间人攻击,配置方式:编辑conf/web.xml,添加 HSTS 过滤器:

    xml

    复制代码
    <filter>
        <filter-name>HstsFilter</filter-name>
        <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
        <init-param>
            <param-name>hstsEnabled</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>hstsMaxAgeSeconds</param-name>
            <param-value>31536000</param-value>
        </init-param>
        <init-param>
            <param-name>hstsIncludeSubDomains</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>hstsPreload</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>HstsFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
  4. 开启证书吊销检查:开启 OCSP 装订,检查证书的吊销状态,防止使用已吊销的证书。

  5. 配置安全的会话缓存:优化 SSL 会话缓存,减少 SSL 握手开销,同时保证会话安全。

8.4 安全漏洞防范

Tomcat 作为开源软件,会不断被发现安全漏洞,生产环境必须做好漏洞防范工作,避免被恶意攻击,同时做好安全加固,减少攻击面。

1. 常见安全漏洞与防范

表格

漏洞类型 漏洞说明 防范措施
远程代码执行漏洞(RCE) 如 CVE-2017-12615、CVE-2020-1938,攻击者通过构造恶意请求,在服务器上执行任意代码,控制服务器 1. 及时升级 Tomcat 到最新稳定版,修复已知漏洞2. 关闭自动部署功能,禁止未授权上传 WAR 包3. 禁用 JSP 上传功能,限制文件上传类型与大小4. 最小化权限运行 Tomcat,禁止使用 root 账号运行
目录遍历 / 文件读取漏洞 攻击者通过构造特殊的 URL 路径,绕过权限控制,读取服务器上的任意文件,如 web.xml、配置文件、系统文件 1. 关闭 DefaultServlet 的目录浏览功能2. 配置安全的 Context 路径,禁用符号链接3. 升级 Tomcat 到最新版本,修复路径解析漏洞4. 前端 WAF 过滤路径遍历字符(../、%2e%2e / 等)
AJP 协议漏洞(GhostCat) CVE-2020-1938,攻击者通过 AJP 端口,构造恶意请求,读取 Web 应用的任意文件,甚至执行代码 1. 不使用 AJP 协议时,直接禁用 AJP 连接器2. 使用 AJP 协议时,必须配置 secret 密钥认证,禁止 secretRequired=false3. 禁止将 AJP 端口对外网暴露,仅允许内网信任 IP 访问
会话固定攻击 攻击者诱使用户使用固定的 Session ID,用户登录后,攻击者使用该 Session ID 获取用户权限 1. 配置 Session Cookie 的 httpOnly=true、secure=true2. 用户登录成功后,重新生成 Session ID3. 配置合理的 Session 超时时间,定期失效 Session
XSS 跨站脚本攻击 攻击者在页面中注入恶意 JavaScript 代码,窃取用户 Cookie、Session 信息,伪造用户操作 1. 开启 Tomcat 的 XSS 防护过滤器,配置 X-XSS-Protection 响应头2. 应用层做好输入过滤与输出转义3. 配置 Content-Security-Policy(CSP)响应头,限制脚本执行
CSRF 跨站请求伪造 攻击者诱导用户在已登录的状态下,访问恶意链接,执行非预期的操作 1. Tomcat 管理界面默认开启 CSRF 防护,生产环境保留2. 应用层添加 CSRF Token 验证3. 配置 SameSite Cookie 属性,限制跨站 Cookie 发送
拒绝服务攻击(DoS) 攻击者通过大量恶意请求,占用 Tomcat 的连接数、线程、内存资源,导致服务不可用 1. 配置合理的 maxConnections、maxThreads、acceptCount 参数2. 配置连接超时、请求超时,释放无效连接3. 前端 Nginx 配置限流、CC 防护,过滤恶意请求4. 禁用 TRACE、OPTIONS 等不必要的 HTTP 方法
2. 生产环境安全加固最佳实践
  1. 版本管理

    • 生产环境使用 Tomcat 最新稳定版,定期更新,修复已知安全漏洞。
    • 关注 Tomcat 官方安全公告,出现高危漏洞时,及时升级或配置临时防护措施。
    • 禁止使用已停止维护的版本(如 Tomcat 7 及以下)。
  2. 减少攻击面

    • 删除 webapps 目录下所有默认应用,禁用管理界面,如需使用必须限制 IP 访问。
    • 禁用未使用的连接器、协议、组件,关闭不必要的端口。
    • 关闭自动部署、热部署功能,生产环境禁止在线部署应用。
    • 禁用 TRACE、PUT、DELETE、OPTIONS 等不必要的 HTTP 方法。
  3. 权限最小化

    • 禁止使用 root/Administrator 管理员账号运行 Tomcat,创建专用的普通用户账号运行 Tomcat,仅赋予最小必要权限。
    • 严格控制 Tomcat 目录的文件权限,禁止其他用户有写入权限,配置文件、密钥文件仅运行用户可读。
    • 应用部署目录禁止有执行权限,防止上传恶意脚本执行。
  4. 网络安全防护

    • Tomcat 不直接对外网暴露,前端使用 Nginx/Apache 作为反向代理,仅开放 80/443 端口,Tomcat 端口仅对内网开放。
    • 防火墙限制 Tomcat 端口的访问 IP,仅允许信任的服务器访问。
    • 配置 WAF Web 应用防火墙,过滤恶意请求、SQL 注入、XSS、路径遍历等攻击。
    • 所有对外请求强制使用 HTTPS,禁用 HTTP 明文传输。
  5. 安全配置加固

    • 配置 HTTP 安全响应头:X-Frame-Options(防止点击劫持)、X-Content-Type-Options(防止 MIME 类型嗅探)、X-XSS-Protection(XSS 防护)、CSP(内容安全策略)。
    • 关闭服务器版本信息泄露,修改 server.xml 的 Connector 节点,添加server="Unknown",隐藏 Tomcat 版本号。
    • 配置合理的请求大小限制,防止大请求体攻击。
    • 开启访问日志,记录所有请求,方便攻击溯源与审计。
  6. 监控与审计

    • 建立常态化的安全监控,实时监控 Tomcat 的异常访问、错误日志、资源占用,及时发现攻击行为。
    • 定期进行安全扫描、渗透测试,发现安全漏洞及时修复。
    • 定期审计配置文件、用户权限、日志信息,排查安全隐患。

第九章:集群与负载均衡

随着业务量的增长,单台 Tomcat 实例的并发能力与可用性无法满足需求,需要搭建 Tomcat 集群,通过负载均衡将请求分发到多个 Tomcat 节点,提升系统的并发处理能力、可用性与容灾能力。

9.1 集群架构原理

Tomcat 集群是指将多个 Tomcat 实例组成一个集群,对外提供统一的服务,所有节点提供相同的服务,通过负载均衡器实现请求分发,核心解决两个问题:高并发高可用

1. 核心集群架构

plaintext

复制代码
┌─────────────────────────────────────────────────────────┐
│                    客户端(浏览器)                       │
└───────────────────────────┬─────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────┐
│                负载均衡器(Nginx/Apache)                │
│  作用:接收客户端请求,按照负载均衡策略分发到后端Tomcat节点 │
└───────────┬───────────────────────┬─────────────────────┘
            ↓                       ↓
┌─────────────────────┐   ┌─────────────────────┐
│   Tomcat节点1       │   │   Tomcat节点2       │
│  192.168.1.10:8080 │   │  192.168.1.11:8080 │
└─────────────────────┘   └─────────────────────┘
            ↓                       ↓
┌─────────────────────────────────────────────────────────┐
│              共享存储/中间件(Redis/数据库)             │
│  作用:实现Session共享、业务数据共享、配置共享           │
└─────────────────────────────────────────────────────────┘
2. 集群核心组件
  1. 负载均衡器:集群的入口,接收所有客户端请求,按照预设的负载均衡策略,将请求分发到后端的 Tomcat 节点,同时实现健康检查,自动剔除故障节点,保证服务可用性。
  2. Tomcat 集群节点:后端的多个 Tomcat 实例,部署相同的 Web 应用,处理负载均衡器分发的请求,所有节点功能完全一致,互为备份。
  3. 会话共享机制:解决集群环境下的 Session 问题,保证用户的请求无论分发到哪个节点,都能获取到正确的 Session 信息,避免用户重复登录。
  4. 共享存储 / 中间件:实现集群节点之间的数据共享,如 Session 数据、缓存数据、业务数据,保证所有节点的数据一致性。
3. 集群核心优势
  • 高并发处理:多台服务器同时处理请求,线性提升系统的并发处理能力,支撑更大的业务流量。
  • 高可用 / 容灾:部分节点故障时,负载均衡器自动将请求分发到正常节点,服务不会中断,实现故障自动转移,提升系统可用性。
  • 弹性伸缩:可根据业务流量,动态增加 / 减少 Tomcat 节点,实现资源的弹性扩缩容,降低运维成本。
  • 灰度发布:可实现应用的灰度发布,先更新部分节点,验证无问题后,全量更新,降低发布风险。

9.2 Session 复制机制

集群环境下,用户的请求可能被分发到任意一个 Tomcat 节点,必须保证 Session 数据在所有节点之间共享,否则会出现用户登录状态丢失、重复登录的问题,Tomcat 提供了原生的 Session 复制机制,同时支持第三方的 Session 共享方案。

1. 原生 Session 复制机制

Tomcat 原生的 Session 复制基于组播(Multicast)实现,集群节点之间通过组播通信,Session 数据发生变化时,自动同步到集群中的所有其他节点,保证所有节点的 Session 数据完全一致。

(1)Session 复制核心原理
  1. 集群中的 Tomcat 节点通过组播发现彼此,建立集群通信。
  2. 当某个节点创建 Session、修改 Session 属性时,会将 Session 数据通过 TCP 单播 / 组播同步到集群中的其他所有节点。
  3. 所有节点的 Session 数据保持完全一致,用户的请求无论分发到哪个节点,都能获取到相同的 Session 数据。
  4. 节点故障时,其他节点不受影响,Session 数据不会丢失,用户请求可正常处理。
(2)Session 复制配置步骤
  1. 开启集群配置 :编辑所有 Tomcat 节点的conf/server.xml,在 Engine 节点下添加 Cluster 配置,开启集群功能。基础配置示例:

    xml

    复制代码
    <Engine name="Catalina" defaultHost="localhost">
        <!-- 集群配置 -->
        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">
            <!-- 组播成员发现:配置组播地址与端口,所有集群节点必须一致 -->
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000" />
            <!-- TCP单播通信:节点之间Session数据同步 -->
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="auto"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6" />
            <!-- 发送器配置 -->
            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
                <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
            </Sender>
            <!-- 拦截器配置:处理Session复制逻辑 -->
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor" />
            <!-- Session复制阀:触发Session数据同步 -->
            <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;" />
            <!-- 集群部署器:实现WAR包集群同步部署(可选) -->
            <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                      tempDir="/tmp/war-temp/"
                      deployDir="/tmp/war-deploy/"
                      watchDir="/tmp/war-watch/"
                      watchEnabled="false" />
            <!-- Session管理器:实现Session复制 -->
            <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
        </Cluster>
    
        <!-- Host节点配置 -->
        <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
        </Host>
    </Engine>
  2. 应用配置 :修改 Web 应用的WEB-INF/web.xml,添加<distributable/>标签,开启应用的分布式支持,该应用的 Session 才会被复制。

    xml

    复制代码
    <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
             version="6.0">
        <!-- 开启分布式支持,启用Session复制 -->
        <distributable/>
        
        <!-- 其他配置 -->
    </web-app>
  3. 配置注意事项

    • 所有集群节点的组播地址address、端口port必须完全一致。
    • Receiver 的address配置为当前节点的 IP 地址,或auto自动获取,port默认 4000,同一台服务器的多个节点需配置不同端口,避免端口冲突。
    • 服务器防火墙必须开放组播端口 45564、TCP 通信端口 4000-4010,否则节点之间无法通信。
    • Session 中存储的对象必须实现java.io.Serializable序列化接口,否则无法同步。
(3)Session 管理器类型

Tomcat 提供了两种 Session 复制管理器,适用于不同的集群规模:

  1. DeltaManager(增量复制管理器,默认)

    • 核心原理:Session 数据发生变化时,将增量变化同步到集群中的所有节点,全节点复制。
    • 优势:配置简单,稳定性高,节点故障时 Session 数据不会丢失,可用性高。
    • 劣势:集群节点数量多时,同步开销大,性能下降明显,仅适合小规模集群(4 节点以内)。
  2. BackupManager(备份复制管理器)

    • 核心原理:Session 数据发生变化时,仅同步到一个备份节点,同时记录 Session 的主节点与备份节点,非全节点复制。
    • 优势:同步开销小,性能高,集群规模扩大时性能影响小,适合中大型集群(4 节点以上)。
    • 劣势:配置复杂,主备节点同时故障时,Session 数据会丢失,可用性略低于 DeltaManager。
2. 第三方 Session 共享方案

Tomcat 原生的 Session 复制仅适合小规模集群,大规模集群推荐使用第三方 Session 共享方案,核心是将 Session 数据统一存储在共享中间件中,所有 Tomcat 节点从共享中间件中读取 / 写入 Session 数据,实现 Session 共享。

常用方案对比:

表格

方案 核心原理 优势 劣势 适用场景
Redis Session 共享 将 Session 数据存储在 Redis 中,Tomcat 通过自定义 SessionManager,从 Redis 中读写 Session 数据 性能高、支持大规模集群、扩展性强、Session 数据持久化、跨机房集群支持 需要额外部署 Redis 集群,引入第三方依赖 中大型生产集群、高并发场景、跨机房集群,最主流的方案
数据库 Session 共享 将 Session 数据存储在数据库中,Tomcat 通过 JDBCRealm / 自定义管理器读写 Session 数据 配置简单、数据持久化、无需额外中间件 性能低,数据库压力大,不适合高并发场景 小型集群、低并发场景、对性能要求不高的场景
会话保持(IP Hash) 负载均衡器根据客户端 IP,将同一个 IP 的请求始终分发到同一个 Tomcat 节点,无需 Session 共享 配置简单、无需修改 Tomcat 配置、无同步开销 节点故障时,Session 数据丢失,负载不均衡,不适合动态 IP 场景 简单集群、测试环境、对可用性要求不高的场景

生产环境最佳实践:推荐使用 Nginx 负载均衡 + Redis Session 共享方案,性能高、扩展性强、稳定性好,是目前最主流的 Tomcat 集群方案,Spring Session 框架可快速实现 Redis Session 共享,无需修改 Tomcat 配置。

9.3 负载均衡配置

负载均衡器是 Tomcat 集群的核心入口,负责请求分发、健康检查、故障转移,常用的负载均衡器有 Nginx、Apache HTTP Server、HAProxy,其中 Nginx 是目前最主流的选择,轻量、高性能、配置简单。

1. 负载均衡核心策略

常用的负载均衡策略,适用于不同的业务场景:

表格

策略 原理 优势 劣势 适用场景
轮询(默认) 请求按顺序依次分发到后端 Tomcat 节点,一个接一个 配置简单、负载均匀、无状态 不考虑节点的性能差异、负载情况 所有节点配置相同、无状态服务、请求处理耗时相近的场景
加权轮询 给每个节点设置权重,权重越高,分发的请求越多 可根据节点的性能配置权重,负载更合理 需要手动配置权重,无法动态调整 节点配置不同、性能有差异的场景
最小连接数 请求分发到当前活跃连接数最少的节点 动态适配节点的负载情况,避免节点过载 增加了负载均衡器的开销,需要统计连接数 请求处理耗时差异大、长连接场景
IP Hash 根据客户端 IP 的 Hash 值,分发到固定的节点,同一个 IP 的请求始终到同一个节点 实现简单的会话保持,无需 Session 共享 节点故障时 Session 丢失,容易导致负载不均衡 简单会话保持、无 Session 共享方案的场景
URL Hash 根据请求 URL 的 Hash 值,分发到固定的节点,同一个 URL 的请求始终到同一个节点 可实现缓存命中,提升后端缓存利用率 负载均衡性一般,节点故障影响大 静态资源集群、缓存服务场景
2. Nginx 负载均衡完整配置示例

需求:搭建 2 个 Tomcat 节点的集群,Nginx 作为负载均衡器,实现加权轮询策略,开启健康检查,自动剔除故障节点。

  1. Nginx 核心配置(nginx.conf):

nginx

复制代码
http {
    # 定义Tomcat集群节点池
    upstream tomcat_cluster {
        # 后端Tomcat节点,weight为权重,值越大分发的请求越多
        server 192.168.1.10:8080 weight=1 max_fails=2 fail_timeout=30s;
        server 192.168.1.11:8080 weight=1 max_fails=2 fail_timeout=30s;
        # 备用节点,所有主节点故障时启用
        # server 192.168.1.12:8080 backup;
        # 最大失败次数:2次请求失败,认为节点故障
        # 故障超时时间:30秒内不再向故障节点分发请求,30秒后重试
    }

    server {
        listen 80;
        server_name www.test.com;

        # 静态资源由Nginx处理,实现动静分离
        location ~* \.(html|css|js|png|jpg|gif|ico|woff|woff2)$ {
            root /usr/local/nginx/static;
            expires 7d;
            add_header Cache-Control "public, max-age=604800";
        }

        # 动态请求转发到Tomcat集群
        location / {
            # 反向代理到Tomcat集群
            proxy_pass http://tomcat_cluster;
            # 传递客户端真实IP给Tomcat
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            # 代理超时配置
            proxy_connect_timeout 10s;
            proxy_read_timeout 60s;
            proxy_send_timeout 60s;
            # 故障转移:当节点返回错误、超时,自动切换到下一个节点
            proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
            proxy_next_upstream_tries 2;
        }

        # 健康检查接口(可选)
        location /status {
            stub_status;
            allow 127.0.0.1;
            deny all;
        }
    }

    # HTTPS配置(生产环境推荐)
    server {
        listen 443 ssl http2;
        server_name www.test.com;

        # SSL证书配置
        ssl_certificate conf/cert/certificate.crt;
        ssl_certificate_key conf/cert/private.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1d;

        # 静态资源处理
        location ~* \.(html|css|js|png|jpg|gif|ico|woff|woff2)$ {
            root /usr/local/nginx/static;
            expires 7d;
        }

        # 动态请求转发
        location / {
            proxy_pass http://tomcat_cluster;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_connect_timeout 10s;
            proxy_read_timeout 60s;
            proxy_send_timeout 60s;
            proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
        }
    }

    # HTTP强制跳转HTTPS
    server {
        listen 80;
        server_name www.test.com;
        return 301 https://$server_name$request_uri;
    }
}
  1. 核心配置说明:

    • upstream:定义后端 Tomcat 集群节点池,名称自定义,proxy_pass 中引用。
    • weight:节点权重,数值越大,分发的请求越多,可根据服务器性能调整。
    • max_fails/fail_timeout:健康检查配置,节点连续失败 max_fails 次后,在 fail_timeout 时间内不再向该节点分发请求。
    • proxy_set_header:传递客户端真实 IP、域名、协议给 Tomcat,避免 Tomcat 获取到的是 Nginx 的 IP。
    • proxy_next_upstream:故障转移配置,当节点返回错误或超时时,自动将请求转发到下一个节点,保证请求成功处理。
  2. Tomcat 配置调整:为了让 Tomcat 获取到客户端的真实 IP,需要修改 Tomcat 的conf/server.xml,在 Host 节点下添加 RemoteIpValve 配置:

    xml

    复制代码
    <Valve className="org.apache.catalina.valves.RemoteIpValve"
           remoteIpHeader="X-Forwarded-For"
           protocolHeader="X-Forwarded-Proto"
           protocolHeaderHttpsValue="https" />

9.4 与 Nginx/Apache 集成

Tomcat 在生产环境中,很少直接对外暴露,通常会与 Nginx/Apache 等 Web 服务器集成,由 Web 服务器处理静态资源、HTTPS 卸载、负载均衡、安全防护,Tomcat 仅专注于处理动态业务逻辑,提升整体性能与安全性。

1. 与 Nginx 集成

Nginx 是目前最主流的 Web 服务器,轻量、高性能、高并发能力强,配置简单,是 Tomcat 集成的首选方案。

(1)核心集成优势
  1. 动静分离:Nginx 处理静态资源的性能远高于 Tomcat,将静态资源交给 Nginx 处理,动态请求转发给 Tomcat,大幅降低 Tomcat 的压力,提升整体性能。
  2. HTTPS 卸载:Nginx 处理 HTTPS 加解密,性能高于 Tomcat 的 Java JSSE 实现,减少 Tomcat 的 CPU 开销。
  3. 负载均衡:Nginx 可轻松实现 Tomcat 集群的负载均衡,配置灵活,支持多种负载策略。
  4. 安全防护:Nginx 可实现 IP 黑白名单、限流、CC 防护、WAF 防护,屏蔽恶意请求,保护后端 Tomcat。
  5. 缓存加速:Nginx 可实现静态资源、动态页面的缓存,减少后端请求,提升访问速度。
  6. 反向代理:隐藏 Tomcat 的内网地址,避免 Tomcat 直接对外暴露,提升系统安全性。
(2)集成方式
  • HTTP 反向代理:最常用的集成方式,Nginx 通过 HTTP 协议将请求转发给 Tomcat,配置简单,兼容性好,无需额外配置,详细配置见 9.3 节。
  • AJP 协议代理:Nginx 通过 AJP 协议与 Tomcat 通信,性能略高于 HTTP 协议,需要配置 AJP 连接器与密钥,适合需要保留完整客户端信息的场景,详细配置见 6.2 节。
2. 与 Apache HTTP Server 集成

Apache HTTP Server 是老牌的 Web 服务器,模块丰富,兼容性好,对动态内容的处理能力强,与 Tomcat 是同属 Apache 基金会的产品,集成度高。

(1)核心集成优势
  1. 模块丰富:Apache 有大量的官方模块,功能全面,支持多种协议、认证方式、扩展功能。
  2. AJP 协议原生支持 :Apache 原生支持 AJP 协议,通过mod_proxy_ajp模块与 Tomcat 深度集成,性能高,配置简单。
  3. 动态内容处理:对 PHP、CGI 等动态内容的支持更好,适合同时运行 Java Web 与 PHP 应用的场景。
  4. 稳定性强:Apache 的稳定性经过长期验证,适合企业级生产环境。
(2)集成方式

Apache 与 Tomcat 集成主要有两种方式,推荐使用mod_proxy_ajp反向代理方式。

  1. **mod_proxy_ajp 反向代理(推荐)**核心配置示例:

    apache

    复制代码
    # 开启必要的模块
    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
    LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
    LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
    
    # 定义Tomcat集群
    <Proxy balancer://tomcat_cluster>
        BalancerMember ajp://192.168.1.10:8009 loadfactor=1 route=node1 secret=AJP@Secret123456
        BalancerMember ajp://192.168.1.11:8009 loadfactor=1 route=node2 secret=AJP@Secret123456
        ProxySet lbmethod=byrequests
    </Proxy>
    
    # 虚拟主机配置
    <VirtualHost *:80>
        ServerName www.test.com
        DocumentRoot "/var/www/html"
    
        # 静态资源由Apache处理
        Alias /static "/var/www/html/static"
        <Directory "/var/www/html/static">
            Options Indexes FollowSymLinks
            AllowOverride None
            Require all granted
            ExpiresActive On
            ExpiresDefault "access plus 7 days"
        </Directory>
    
        # 动态请求转发到Tomcat集群
        ProxyPass /static !
        ProxyPass / balancer://tomcat_cluster/
        ProxyPassReverse / balancer://tomcat_cluster/
        ProxyPreserveHost On
    </VirtualHost>
  2. mod_jk 模块传统的集成方式,通过专门的 JK 模块实现 Apache 与 Tomcat 的通信,配置复杂,目前已逐渐被 mod_proxy_ajp 替代,不推荐新环境使用。

3. Nginx 与 Apache 集成方案对比

表格

对比维度 Nginx + Tomcat Apache + Tomcat
静态资源性能 极高,事件驱动模型,高并发下性能远超 Apache 良好,进程模型,高并发下性能不如 Nginx
并发能力 极强,支持万级并发连接,内存占用低 中等,高并发下进程开销大,内存占用高
配置复杂度 简单,配置文件简洁易懂 复杂,模块多,配置繁琐
模块丰富度 丰富,第三方模块多,核心模块精简 极丰富,官方模块全面,企业级功能完善
反向代理能力 极强,原生支持多种负载策略、健康检查 良好,需要额外模块支持,配置复杂
适用场景 高并发、大流量场景、静态资源多的 Web 应用、微服务架构 企业级应用、多语言混合部署、需要丰富模块功能的场景

生产环境最佳实践:绝大多数场景推荐使用 Nginx + Tomcat 的集成方案,性能更高、配置更简单、运维成本更低;仅在需要 Apache 的特定模块、多语言混合部署时,选择 Apache + Tomcat 方案。

第十章:监控与日志

Tomcat 的监控与日志是生产环境问题定位、性能调优、安全审计的核心能力,本章覆盖监控配置、日志体系、分析方法与常用工具。

10.1 JMX 监控配置

JMX(Java Management Extensions)是 Java 原生的监控管理标准,Tomcat 内置了完整的 JMX MBean 组件,可实现对连接器、线程池、内存、类加载、Web 应用等全维度的监控与动态配置。

10.1.1 本地 JMX 启用

Tomcat 启动时默认开启本地 JMX 支持,无需额外配置,本地可直接通过 JDK 自带工具(JConsole、VisualVM)连接,前提是启动 Tomcat 的 JDK 与监控工具的 JDK 版本兼容。

10.1.2 远程 JMX 配置(生产环境必备)

远程 JMX 需修改 bin/catalina.sh(Linux)/ bin/catalina.bat(Windows),在 JAVA_OPTS 中添加以下参数,分为无认证基础配置带认证安全配置

基础远程配置(测试环境用)

bash

运行

复制代码
# Linux catalina.sh 开头添加
JAVA_OPTS="$JAVA_OPTS
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8999
-Dcom.sun.management.jmxremote.rmi.port=8999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=192.168.1.100" # Tomcat 服务器IP
生产安全配置(带认证 + SSL)
  1. 开启身份认证,修改 JAVA_OPTS: bash

    运行

    复制代码
    JAVA_OPTS="$JAVA_OPTS
    -Dcom.sun.management.jmxremote
    -Dcom.sun.management.jmxremote.port=8999
    -Dcom.sun.management.jmxremote.rmi.port=8999
    -Dcom.sun.management.jmxremote.ssl=true
    -Dcom.sun.management.jmxremote.authenticate=true
    -Dcom.sun.management.jmxremote.password.file=$CATALINA_BASE/conf/jmxremote.password
    -Dcom.sun.management.jmxremote.access.file=$CATALINA_BASE/conf/jmxremote.access
    -Djava.rmi.server.hostname=你的服务器公网/内网IP"
  2. 配置权限与密码文件:

    • 复制 JDK 模板文件:cp $JAVA_HOME/jre/lib/management/jmxremote.password.template $CATALINA_BASE/conf/jmxremote.password

    • 编辑 jmxremote.access(权限配置):

      properties

      复制代码
      monitorRole readonly  # 只读权限,用于监控
      controlRole readwrite # 读写权限,可动态修改配置
    • 编辑 jmxremote.password(密码配置):

      properties

      复制代码
      monitorRole 你的只读密码
      controlRole 你的读写密码
    • 权限加固(Linux 必须执行,否则启动报错): bash

      运行

      复制代码
      chmod 600 $CATALINA_BASE/conf/jmxremote.password
      chown tomcat:tomcat $CATALINA_BASE/conf/jmxremote.password
  3. 防火墙放行 8999 端口,确保服务器与监控端网络互通。

10.1.3 常用 JMX 监控客户端
  • JConsole:JDK 自带,可视化查看 MBean、内存、线程、CPU 占用,支持远程连接,适合快速排查。
  • VisualVM:JDK 自带 / 独立安装,功能更强大,支持堆内存分析、线程 dump、GC 监控,可安装插件对接 Tomcat 专属指标。
  • Prometheus + Grafana:生产环境主流方案,通过 JMX Exporter 暴露 Tomcat 指标,实现持久化监控、告警与可视化大盘。

10.2 日志级别与输出

Tomcat 采用 JULI(Java Util Logging Implementation)作为默认日志框架,是 JDK java.util.logging 的扩展,解决了原生 JUL 无法实现多应用隔离日志的问题,支持容器级、应用级独立日志配置。

10.2.1 日志级别说明

从高到低(级别越高,输出日志越少),Tomcat 支持以下日志级别:

表格

级别 含义 适用场景
OFF 关闭所有日志输出 完全禁用日志
SEVERE 严重错误,导致系统 / 功能无法运行 启动失败、OOM、核心组件崩溃
WARNING 警告信息,不影响运行但存在潜在风险 配置不规范、资源即将耗尽
INFO 常规运行信息,默认级别 服务启动、应用部署完成
CONFIG 配置相关信息 组件初始化、配置加载详情
FINE 详细调试信息 开发调试、流程追踪
FINER 更详细的调试信息 深度问题定位
FINEST 最详细的调试信息 源码级调试
ALL 输出所有日志 全量调试
10.2.2 核心日志配置文件

Tomcat 日志核心配置文件为 conf/logging.properties,控制容器全局日志,Web 应用可通过 WEB-INF/classes/logging.properties 实现应用级独立配置。

核心配置示例

properties

复制代码
# 1. 全局日志级别与处理器
handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
.level = INFO

# 2. Catalina容器日志配置(catalina.out/catalina.YYYY-MM-DD.log)
1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.
1catalina.org.apache.juli.FileHandler.suffix = .log
1catalina.org.apache.juli.FileHandler.rotatable = true # 按天轮转
1catalina.org.apache.juli.FileHandler.maxDays = 30     # 日志保留30天

# 3. 控制台输出配置(启动时终端输出)
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter

# 4. 细分模块日志级别(按需调整)
org.apache.catalina.core.level = WARNING
org.apache.catalina.startup.level = INFO
org.apache.coyote.level = WARNING
org.apache.tomcat.util.net.level = WARNING

# 5. localhost日志(应用部署、上下文相关日志)
2localhost.org.apache.juli.FileHandler.level = FINE
2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.FileHandler.prefix = localhost.
10.2.3 关键日志文件说明

表格

日志文件 核心内容
catalina.out 标准输出 / 错误流,包含 Tomcat 启动、运行、异常堆栈,是问题排查首选文件
catalina.YYYY-MM-DD.log Catalina 容器的结构化日志,按天轮转,与 catalina.out 内容部分重叠
localhost.YYYY-MM-DD.log Web 应用上下文初始化、销毁、JSP 编译、Servlet 加载相关日志
localhost_access_log.YYYY-MM-DD.txt 访问日志,记录所有 HTTP 请求详情,见 10.3 节
manager.YYYY-MM-DD.log Tomcat Manager 管理应用的操作日志
host-manager.YYYY-MM-DD.log 虚拟主机管理的操作日志
10.2.4 日志输出优化
  1. 生产环境建议关闭 FINE 及以下级别的日志,减少磁盘 IO 与性能损耗;
  2. 配置 maxDays 自动清理过期日志,避免磁盘占满;
  3. 大流量场景可开启异步日志,修改 FileHandler 配置添加 org.apache.juli.AsyncFileHandler
  4. 避免在 catalina.out 中输出大量重复日志,可通过调整模块级别过滤无效信息。

10.3 访问日志分析

访问日志(Access Log)记录了所有客户端对 Tomcat 的 HTTP 请求详情,是接口性能分析、安全审计、流量统计、异常请求排查的核心依据,由 Tomcat 的 AccessLogValve 组件实现。

10.3.1 访问日志配置

conf/server.xml<Host> 标签内,默认已内置 AccessLogValve 配置,生产环境可按需优化:

xml

复制代码
<Valve className="org.apache.catalina.valves.AccessLogValve"
       directory="logs"
       prefix="localhost_access_log"
       suffix=".txt"
       pattern="%h %l %u %t &quot;%r&quot; %s %b %D &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot;"
       rotatable="true"
       maxDays="30"
       requestAttributesEnabled="true" />
核心 pattern 格式符说明

表格

格式符 含义
%h 客户端 IP 地址
%l 客户端标识,通常为 -
%u 远程认证的用户名,未认证为 -
%t 请求时间,格式为 [日 / 月 / 年:时: 分:秒 时区]
%r 请求行原始内容(请求方法 + URI + 协议版本)
%s HTTP 响应状态码(200/404/500 等)
%b 响应体字节数,不包含 HTTP 头,无响应体为 -
%B 响应体字节数,无响应体为 0
%D 请求处理耗时,单位:毫秒(核心指标,用于慢请求分析)
%T 请求处理耗时,单位:秒
%{xxx}i 获取请求头中的 xxx 字段,如 %{User-Agent} i、%{Referer} i
%{xxx}o 获取响应头中的 xxx 字段
10.3.2 常用命令行快速分析(Linux 环境)

生产环境最便捷的分析方式,无需额外安装工具,直接通过 grep、awk、sort 等命令实现快速统计。

  1. 统计状态码分布 bash

    运行

    复制代码
    awk '{print $9}' localhost_access_log.2024-05-20.txt | sort | uniq -c | sort -nr
  2. 统计 TOP10 访问量最高的 IP bash

    运行

    复制代码
    awk '{print $1}' localhost_access_log.2024-05-20.txt | sort | uniq -c | sort -nr | head -10
  3. 筛选慢请求(耗时超过 1000ms) bash

    运行

    复制代码
    awk '$(NF-6) > 1000' localhost_access_log.2024-05-20.txt
  4. 统计 QPS(每秒请求数) bash

    运行

    复制代码
    awk '{print $4}' localhost_access_log.2024-05-20.txt | uniq -c | sort -nr | head -10
  5. 筛选 500 错误请求详情 bash

    运行

    复制代码
    grep ' 500 ' localhost_access_log.2024-05-20.txt
  6. 统计 TOP10 访问量最高的接口 bash

    运行

    复制代码
    awk '{print $7}' localhost_access_log.2024-05-20.txt | sort | uniq -c | sort -nr | head -10
10.3.3 专业分析工具
  • GoAccess:轻量级开源日志分析工具,支持实时解析、生成可视化 HTML 报表,支持 Tomcat 访问日志格式,适合单节点快速分析。
  • AWStats:老牌日志分析工具,支持多维度流量统计、SEO 分析、客户端统计,适合长期日志归档分析。
  • ELK Stack(Elasticsearch + Logstash + Kibana):生产环境分布式集群主流方案,实现日志集中采集、存储、检索、可视化大屏与告警。
  • Prometheus + Grafana:通过 Access Log Exporter 提取指标,实现流量、状态码、耗时的时序监控与告警。

10.4 性能监控工具

Tomcat 性能监控分为自带工具JDK 原生工具第三方专业工具三类,覆盖从快速排查到生产全链路监控的全场景。

10.4.1 Tomcat 自带监控工具
  1. Manager 状态页Tomcat 内置的 Manager 应用提供了可视化监控页面,开启方式:

    • 编辑 conf/tomcat-users.xml,添加管理员用户:

      xml

      复制代码
      <role rolename="manager-gui"/>
      <role rolename="manager-status"/>
      <user username="tomcat_admin" password="你的密码" roles="manager-gui,manager-status"/>
    • 访问 http://ip:8080/manager/status,可查看:

      • JVM 内存、线程池状态
      • HTTP/AJP 连接器的线程使用、请求数、错误数、耗时
      • 每个 Web 应用的会话数、上下文信息
    • 生产环境建议限制 Manager 访问 IP,编辑 webapps/manager/META-INF/context.xml,配置 RemoteAddrValve 白名单。

  2. Host-Manager 虚拟主机监控用于监控和管理 Tomcat 虚拟主机,可查看各 Host 的部署状态、上下文配置,适合多虚拟主机场景。

10.4.2 JDK 原生命令行工具

表格

工具 核心功能 Tomcat 常用命令示例
jps 查看 Java 进程 PID,快速获取 Tomcat 进程号 jps -l 输出完整主类名,找到 Bootstrap 对应的 PID
jstat 实时监控 JVM GC、内存、类加载状态,无侵入,适合生产环境 jstat -gc 进程PID 1000 10 每秒 1 次,共 10 次,查看 GC 详情;jstat -gcutil PID 查看内存占用率
jstack 生成线程快照,排查死锁、线程阻塞、CPU 占用过高、线程池耗尽问题 jstack -l 进程PID > thread_dump.log 输出线程 dump 到文件,分析线程状态
jmap 生成堆内存快照,排查 OOM、内存泄漏、对象占用过高问题 jmap -dump:format=b,file=heap_dump.hprof 进程PID 生成堆 dump 文件;`jmap -histo PID head -20` 查看 TOP 占用对象
jhat 堆 dump 文件分析工具,配合 jmap 使用,生成可视化 HTML 分析页面 jhat heap_dump.hprof 启动 HTTP 服务,默认 7000 端口,浏览器访问分析
10.4.3 第三方可视化与生产监控工具
  1. VisualVM:JDK 自带的全能型可视化工具,集成了内存、线程、GC、MBean 监控,支持堆 dump 分析、性能采样,可安装插件对接 Tomcat 专属指标,适合开发、测试环境深度排查。
  2. Arthas:Alibaba 开源的 Java 诊断工具,无侵入、在线调试,支持查看 Tomcat 类加载信息、方法调用耗时、热更新代码、排查类冲突,是生产环境问题定位神器。
  3. Prometheus + Grafana :生产环境集群监控首选方案,通过 jmx_exporter 暴露 Tomcat 全量指标,Grafana 搭建可视化大盘,支持自定义告警规则,适配容器化、分布式部署。
  4. APM 全链路监控工具:SkyWalking、Pinpoint、Cat 等,支持 Tomcat 接入,实现从前端请求到后端服务、数据库的全链路追踪,可定位慢接口、异常调用、分布式事务问题,适合微服务架构。

第十一章:常见问题与故障排查

本章汇总 Tomcat 生产、开发环境高频出现的故障,提供标准化的排查思路与解决方案,覆盖启动、内存、连接、类加载、部署五大核心场景。

11.1 启动失败常见原因

Tomcat 启动失败是最常见的问题,核心排查逻辑是:先看 catalina.out 日志定位报错信息,再按优先级排查核心原因

表格

故障分类 常见原因 排查与解决方案
端口占用 8080/8005/8009 端口被其他进程占用,是最高频的启动失败原因 1. Linux:`ss -tulnp grep 8080 查看占用进程;Windows:netstat -ano findstr 8080`2. 解决方案:kill 占用进程,或修改 server.xml 中 Connector 端口、Server 端口
JDK 版本不兼容 Tomcat 版本与 JDK 版本不匹配,如 Tomcat 10+ 要求 JDK 11+,Tomcat 9 要求 JDK 8+ 1. 查看官方版本兼容矩阵,确认 JDK 版本符合要求2. 检查 JAVA_HOME 环境变量是否正确配置,是否存在多 JDK 冲突
配置文件语法错误 server.xml/web.xml/context.xml 标签未闭合、属性错误、格式异常 1. 查看 catalina.out 中的 XML 解析报错,定位错误文件与行号2. 恢复默认配置文件,逐步修改验证
权限不足 Linux 环境下 Tomcat 运行用户无日志、webapps、conf 目录的读写权限 1. 检查目录权限:ls -l $CATALINA_BASE2. 授权:chown -R tomcat:tomcat $CATALINA_BASE,避免使用 root 用户启动
依赖缺失 / 损坏 bin 目录下启动脚本缺失、lib 目录核心 jar 包损坏、JDK 安装包不完整 1. 校验 Tomcat 安装包完整性,重新解压官方安装包2. 检查 JDK 是否正常,执行 java -version 验证
虚拟主机配置错误 server.xml 中 Host 配置重复、appBase 目录不存在、name 属性无效 1. 注释新增的 Host 配置,使用默认 localhost 启动验证2. 检查 appBase 目录是否存在,权限是否正确
内存参数配置错误 catalina.sh 中 JVM 参数格式错误、数值超出服务器内存限制 1. 注释新增的 JVM 参数,使用默认配置启动2. 检查 Xmx/Xms 参数是否合理,不可超过服务器可用内存

11.2 内存溢出问题

OOM(Out Of Memory)是 Tomcat 生产环境最严重的故障之一,会导致服务卡顿、崩溃、无法响应请求,核心分为 4 类,需针对性排查。

11.2.1 堆内存溢出(java.lang.OutOfMemoryError: Java heap space)

核心原因

  1. 堆内存配置过小,无法支撑业务流量峰值;
  2. 代码中存在大对象、集合未释放,导致内存泄漏;
  3. 频繁创建短生命周期对象,GC 来不及回收,峰值期溢出;
  4. 数据库查询未分页,一次性加载大量数据到内存。

排查与解决

  1. 调整 JVM 堆内存参数,编辑 catalina.sh: bash

    运行

    复制代码
    # 生产环境建议 Xms 与 Xmx 配置相同值,避免堆内存动态扩容带来的性能损耗
    JAVA_OPTS="$JAVA_OPTS -Xms4g -Xmx4g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_BASE/logs/"
  2. 生成堆 dump 文件后,使用 MAT、VisualVM、JProfiler 分析,定位占用内存最高的对象与代码位置;

  3. 优化代码:避免大对象常驻内存、集合使用后及时清空、数据库查询分页、禁用循环内创建对象;

  4. 优化 GC 策略,根据 JDK 版本选择合适的垃圾收集器(JDK 8 用 G1,JDK 17+ 用 ZGC)。

11.2.2 元空间溢出(java.lang.OutOfMemoryError: Metaspace)

JDK 8 及以上为元空间(Metaspace),JDK 7 及以下为永久代(PermGen)。核心原因

  1. 元空间默认上限受服务器本地内存限制,配置过小导致溢出;
  2. 应用中大量动态生成类(如反射、动态代理、ASM 框架、JSP 动态编译);
  3. 热部署频繁,旧的类加载器未销毁,导致类元信息无法回收,出现类加载器泄漏;
  4. 依赖的第三方 jar 包过多,加载的类数量超出元空间承载能力。

排查与解决

  1. 调整元空间参数,编辑 catalina.sh: bash

    运行

    复制代码
    JAVA_OPTS="$JAVA_OPTS -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
  2. 生产环境关闭频繁热部署,避免类加载器泄漏;

  3. 排查代码中是否存在大量动态生成类的逻辑,优化代理类的创建方式;

  4. 清理无效的第三方依赖,减少类加载数量。

11.2.3 直接内存溢出(java.lang.OutOfMemoryError: Direct buffer memory)

核心原因

  1. NIO 场景下(Tomcat NIO 连接器),直接内存分配超出限制;
  2. Netty、RocketMQ 等框架大量使用直接内存,未合理配置上限;
  3. 直接内存泄漏,堆外内存对象未释放。

排查与解决

  1. 配置直接内存上限,编辑 catalina.sh: bash

    运行

    复制代码
    # 建议不超过堆内存的 1/2
    JAVA_OPTS="$JAVA_OPTS -XX:MaxDirectMemorySize=2g"
  2. 配合 Arthas、NMT(Native Memory Tracking)工具排查堆外内存占用;

  3. 优化框架配置,限制堆外内存的分配阈值。

11.2.4 栈溢出(java.lang.StackOverflowError)

核心原因

  1. 代码中出现无限递归调用,是最常见原因;
  2. 方法调用层级过深,超出线程栈的大小限制;
  3. 线程栈配置过小,无法支撑业务方法调用。

排查与解决

  1. 查看异常堆栈,定位递归调用的代码位置,修复循环递归问题;

  2. 调整线程栈大小,编辑 catalina.sh: bash

    运行

    复制代码
    # 生产环境建议 1m,过小会导致栈溢出,过大会降低可创建的线程总数
    JAVA_OPTS="$JAVA_OPTS -Xss1m"

11.3 连接数异常

Tomcat 连接数异常会导致服务响应慢、请求超时、甚至拒绝服务,核心分为连接数打满、连接状态异常两大类。

11.3.1 连接数打满,请求无法进入

核心现象

  • 服务能 ping 通,但端口无法建立连接,请求超时;
  • manager 状态页显示 HTTP 连接器线程池线程全部处于 busy 状态;
  • 日志中出现 Timeout waiting for available thread 相关报错。

核心原因

  1. 后端应用处理慢(数据库慢查询、第三方接口超时、锁竞争),导致线程被长时间占用,无法释放;
  2. 连接器 maxThreads 配置过小,无法支撑业务并发量;
  3. connectionTimeout 配置过长,空闲连接不释放,占用线程资源;
  4. 突发流量峰值,超出 Tomcat 承载能力。

排查与解决

  1. 执行 jstack 生成线程快照,查看大量线程的阻塞位置,定位慢接口、慢 SQL、锁竞争问题,优先优化业务代码;

  2. 合理调整连接器核心参数,编辑 server.xml: xml

    复制代码
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               maxThreads="400"               # 最大线程数,CPU密集型建议200-400,IO密集型建议400-800
               minSpareThreads="50"           # 核心常驻线程数
               acceptCount="200"               # 等待队列长度,线程满时,请求进入队列等待
               connectionTimeout="6000"        # 连接超时时间,单位ms,生产环境建议3-10秒
               maxConnections="8000"           # 最大连接数,NIO模式下远大于maxThreads
               enableLookups="false"           # 禁用DNS反向解析,提升性能
               maxKeepAliveRequests="1000"     # 长连接最大请求数
               keepAliveTimeout="60000" />     # 长连接超时时间
  3. 配置超时重试机制,避免无效请求长时间占用线程;

  4. 接入限流组件,避免突发流量打满服务。

11.3.2 连接状态异常
  1. TIME_WAIT 过多

    • 原因:短连接场景下,TCP 四次挥手后,主动关闭连接的一方会保持 TIME_WAIT 状态 2MSL,频繁短连接会导致服务器端口耗尽。

    • 解决:开启 TCP 端口复用,优化 Linux 内核参数: bash

      运行

      复制代码
      # 编辑 /etc/sysctl.conf
      net.ipv4.tcp_tw_reuse = 1    # 允许TIME_WAIT套接字重新用于新的TCP连接
      net.ipv4.tcp_tw_recycle = 1  # 快速回收TIME_WAIT套接字
      net.ipv4.tcp_fin_timeout = 30 # 调整FIN_WAIT2超时时间
      net.ipv4.ip_local_port_range = 1024 65535 # 扩大可用端口范围
    • 业务优化:优先使用 HTTP 长连接,减少频繁短连接创建。

  2. CLOSE_WAIT 堆积

    • 原因:被动关闭连接的一方,未调用 close 方法释放连接,导致连接一直处于 CLOSE_WAIT 状态,核心是应用代码问题,或 Tomcat 连接释放逻辑异常。
    • 解决:
      1. 检查代码中 HTTP 客户端、数据库连接、Socket 连接是否正确关闭,必须在 finally 块中执行关闭操作;
      2. 调整 Tomcat 连接器的 soTimeout 配置,强制释放超时连接;
      3. 检查依赖的第三方框架是否存在连接泄漏,升级到稳定版本。

11.4 ClassNotFound 问题解决

ClassNotFound/NoClassDefFoundError 是 Tomcat 开发、部署阶段高频问题,核心与 Tomcat 的类加载机制强相关,需先理解类加载逻辑,再按步骤排查。

11.4.1 先明确 Tomcat 类加载机制(双亲委派模型的打破)

Tomcat 为了实现 Web 应用之间的类隔离,默认打破了 JDK 的双亲委派模型,每个 Web 应用都有独立的 WebAppClassLoader,加载优先级为:

  1. Bootstrap 类加载器(JVM 核心类)
  2. System 类加载器(JVM 扩展类、Tomcat 启动类)
  3. WebAppClassLoader(当前应用 WEB-INF/classes、WEB-INF/lib 下的类)
  4. Common 类加载器(Tomcat lib 目录下的共享类)

核心规则:Web 应用优先加载自己目录下的类,找不到才会委托父加载器加载,这也是类冲突、类找不到的核心诱因。

11.4.2 常见原因与解决方案

表格

异常类型 核心原因 排查与解决方案
ClassNotFoundException JVM 加载类时,在所有类加载器的路径中都找不到该类的字节码文件 1. 确认该类所属的 jar 包是否存在2. 检查 jar 包是否放在正确的目录: - 单个应用使用:放在 WEB-INF/lib 下 - 所有应用共享:放在 Tomcat lib 目录下3. 检查 Maven 依赖的 scope 是否为 provided,导致打包时未打入 jar 包
NoClassDefFoundError 编译时能找到该类,运行时类加载器能找到类文件,但类的初始化失败,或依赖的类缺失 1. 查看异常堆栈的 Caused by,找到类初始化失败的根本原因(静态代码块异常、静态变量初始化失败)2. 检查该类依赖的其他类是否存在,是否有依赖包缺失
NoSuchMethodError 类存在,但方法不存在,核心是 jar 包版本冲突 1. 排查类加载器加载的类版本,使用 Arthas 的 sc -d 类全限定名 查看类来自哪个 jar 包2. Maven 项目执行 mvn dependency:tree 排查包冲突,排除低版本 / 冲突版本3. 避免 Tomcat lib 目录与应用 WEB-INF/lib 目录存在同一个 jar 的不同版本
ClassCastException 同一个类被两个不同的类加载器加载,导致类型转换异常 1. 避免共享类在 Tomcat lib 和应用 WEB-INF/lib 中同时存在2. 对于需要跨应用共享的类,统一放在 Tomcat lib 目录下,由 Common 类加载器加载
11.4.3 标准化排查步骤
  1. 从异常堆栈中获取类的全限定名,确认该类属于哪个第三方依赖,或项目自身的类;
  2. 检查项目打包后的 war 包中,WEB-INF/lib 下是否存在该 jar 包,WEB-INF/classes 下是否存在该 class 文件;
  3. 若为自身类,检查编译打包是否正常,是否存在编译时排除、打包遗漏的情况;
  4. 若为第三方类,检查 Maven/Gradle 依赖配置,是否存在 scope 错误、版本号错误、exclusions 排除了该依赖;
  5. 排查包冲突,确认类加载器加载的类版本是否符合预期;
  6. 检查 Tomcat 类加载配置,是否在 context.xml 中配置了 delegate="true"(开启双亲委派),导致类加载优先级变化。

11.5 部署冲突排查

Tomcat 部署冲突会导致应用启动失败、上下文加载异常、功能不可用,核心分为路径冲突、配置冲突、依赖冲突三大类。

11.5.1 上下文路径冲突

现象 :应用部署后无法访问,日志中出现 Context with name [/xxx] has already been started 报错。原因

  1. webapps 目录下存在同名的 war 包和解压后的文件夹,导致重复部署;
  2. 同一个 Host 下,部署了两个 context-path 完全相同的应用;
  3. conf/Catalina/localhost 目录下存在同名的 xml 配置文件,与 webapps 下的应用重复部署。

解决

  1. 清理 webapps 目录,删除重复的 war 包和文件夹,确保一个上下文路径只对应一个应用;
  2. 检查 conf/Catalina/[Host 名称] 目录下的 xml 配置,删除重复的上下文配置;
  3. 多应用部署时,确保每个应用的 context-path 唯一,通过 war 包名称、Context 标签的 path 属性配置。
11.5.2 端口与主机配置冲突

现象 :应用部署后 Tomcat 启动失败,或部分应用无法访问。原因

  1. server.xml 中配置了多个 Connector,使用了相同的端口;
  2. 多个 Host 配置了相同的 name 属性,导致虚拟主机冲突;
  3. 同一个服务器上启动了多个 Tomcat 实例,使用了相同的端口(8080/8005/8009)。

解决

  1. 检查 server.xml 中所有 Connector 的 port 属性,确保端口唯一不重复;
  2. 多 Tomcat 实例部署时,修改每个实例的 server.xml,确保 HTTP 端口、Server shutdown 端口、AJP 端口全部不重复;
  3. 多虚拟主机配置时,确保每个 Host 的 name 属性唯一,对应不同的域名。
11.5.3 应用内配置与组件冲突

现象 :应用启动成功,但部分功能异常,日志中出现 Servlet/Filter 初始化失败、Bean 重复定义报错。原因

  1. web.xml 中配置了两个相同名称的 Servlet/Filter/Listener,导致覆盖或初始化失败;
  2. 注解配置(@WebServlet/@WebFilter)与 web.xml 配置重复,导致组件重复注册;
  3. Spring 等框架配置中,出现 Bean 名称重复、扫描路径重复,导致 Bean 初始化冲突;
  4. web.xml 中 welcome-file-list、error-page 等配置重复,导致规则覆盖。

解决

  1. 检查 web.xml,确保所有 Servlet/Filter/Listener 的名称唯一,无重复配置;
  2. 避免注解与 XML 重复配置,统一组件注册方式;
  3. 检查框架配置,清理重复的 Bean 定义、重复的包扫描路径;
  4. 合并重复的全局配置,避免规则冲突。
11.5.4 跨应用依赖冲突

现象 :单个应用单独部署正常,多个应用一起部署时,部分应用出现类冲突、功能异常。原因

  1. Tomcat lib 目录下的共享 jar 包,与某个应用 WEB-INF/lib 下的 jar 包版本不一致,导致类加载冲突;
  2. 多个应用使用了同一个全局资源(如数据库连接池、JMX 注册名称),导致资源抢占冲突;
  3. 开启了应用间类共享,不同应用的同名类不同版本,导致类加载异常。

解决

  1. 生产环境优先保持应用隔离,避免在 Tomcat lib 目录下放置业务相关的 jar 包,所有依赖放在各自应用的 WEB-INF/lib 下;
  2. 若需要共享依赖,确保 Tomcat lib 目录下的 jar 包版本,与所有应用的依赖版本兼容;
  3. 多个应用的全局资源配置(如数据源名称、JMX 名称)必须唯一,避免资源抢占;
  4. 非必要不开启类共享,保持 Context 的 delegate 属性为默认 false。

第十二章:高级特性

本章深入 Tomcat 核心高级特性,覆盖 Valve 组件、自定义类加载器、嵌入式 Tomcat、源码编译与调试,适合深度定制化、二次开发与底层原理学习。

12.1 Tomcat Valve 组件

Valve(阀门)是 Tomcat 管道 - 过滤器(Pipeline-Valve)设计模式的核心实现,是 Tomcat 容器级的拦截组件,作用类似于 Java Web 的 Filter,但 Filter 是应用级,Valve 是引擎级 / 主机级 / 上下文级,可实现全局拦截,不受 Web 应用配置影响。

12.1.1 Valve 核心原理

Tomcat 的 Engine、Host、Context 容器都内置了一个 Pipeline(管道),每个 Pipeline 中包含多个 Valve,形成一个阀门链。请求进入容器后,会依次经过 Pipeline 中的所有 Valve,最终到达基础 Valve(基础阀门负责调用子容器的 Pipeline),响应时按逆序返回。

  • 基础 Valve:每个容器的 Pipeline 必须有一个基础 Valve,位于阀门链末端,负责处理请求并调用子容器,如 Engine 的 StandardEngineValve、Host 的 StandardHostValve、Context 的 StandardContextValve。
  • 自定义 Valve:可插入到管道中,在基础 Valve 之前执行,实现请求预处理、响应后处理、访问控制、日志记录等功能。
12.1.2 常用内置 Valve

Tomcat 内置了大量开箱即用的 Valve,可直接在 server.xml 中配置使用,常用如下:

  1. AccessLogValve:访问日志记录 Valve,见 10.3 节,是最常用的内置 Valve,可配置在 Engine/Host/Context 级别。

  2. RemoteAddrValve :IP 访问控制 Valve,实现 IP 黑白名单,示例:

    xml

    复制代码
    <!-- 配置在 Host 标签内,全局IP白名单,仅允许192.168网段和127.0.0.1访问 -->
    <Valve className="org.apache.catalina.valves.RemoteAddrValve"
           allow="192\.168\.\d{1,3}\.\d{1,3}|127\.0\.0\.1"
           deny="192\.168\.1\.100"
           denyStatus="403" />
  3. RemoteHostValve:主机名访问控制 Valve,基于客户端主机名实现黑白名单,用法与 RemoteAddrValve 一致。

  4. ErrorReportValve :错误页面定制 Valve,可自定义 Tomcat 原生错误页面,隐藏服务器版本信息,示例:

    xml

    复制代码
    <Valve className="org.apache.catalina.valves.ErrorReportValve"
           showReport="false"
           showServerInfo="false"
           errorCode.404="/error/404.html"
           errorCode.500="/error/500.html" />
  5. SSLValve:SSL 证书处理 Valve,用于反向代理场景下,传递 SSL 证书信息到后端 Tomcat。

  6. RewriteValve:URL 重写 Valve,实现类似 Nginx 的 rewrite 功能,支持正则匹配 URL 重写、重定向。

12.1.3 自定义 Valve 开发与部署
开发步骤
  1. 引入 Tomcat 依赖,Maven 配置: xml

    复制代码
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-catalina</artifactId>
        <version>你的Tomcat版本</version>
        <scope>provided</scope>
    </dependency>
  2. 继承 ValveBase 类,重写 invoke 方法,实现业务逻辑:

    java

    运行

    复制代码
    import org.apache.catalina.connector.Request;
    import org.apache.catalina.connector.Response;
    import org.apache.catalina.valves.ValveBase;
    import javax.servlet.ServletException;
    import java.io.IOException;
    
    /**
     * 自定义全局请求耗时统计Valve
     */
    public class RequestCostValve extends ValveBase {
    
        // 自定义配置属性,可在xml中配置
        private boolean enableLog = true;
    
        @Override
        public void invoke(Request request, Response response) throws IOException, ServletException {
            // 1. 请求前处理
            long startTime = System.currentTimeMillis();
            String requestUri = request.getRequestURI();
            String clientIp = request.getRemoteAddr();
    
            try {
                // 2. 调用下一个Valve,必须执行,否则请求会中断
                getNext().invoke(request, response);
            } finally {
                // 3. 响应后处理
                long costTime = System.currentTimeMillis() - startTime;
                if (enableLog && costTime > 1000) {
                    // 记录慢请求日志
                    System.out.printf("慢请求告警:IP[%s], URI[%s], 耗时[%d]ms%n", clientIp, requestUri, costTime);
                }
            }
        }
    
        // getter和setter方法,xml配置的属性会通过setter注入
        public boolean isEnableLog() {
            return enableLog;
        }
    
        public void setEnableLog(boolean enableLog) {
            this.enableLog = enableLog;
        }
    }
  3. 编译打包,生成 jar 包。

部署与配置
  1. 将 jar 包放入 Tomcat 的 lib 目录(Valve 是容器级组件,必须由 Common 类加载器加载);

  2. 编辑 conf/server.xml,在 Engine/Host/Context 标签内添加 Valve 配置:

    xml

    复制代码
    <!-- 配置在Host标签内,对该Host下的所有应用生效 -->
    <Valve className="com.tomcat.custom.RequestCostValve"
           enableLog="true" />
  3. 重启 Tomcat,Valve 即可生效。

12.1.4 Valve 使用注意事项
  1. Valve 执行在 Servlet 容器之前,无法获取 Spring 等框架的上下文,仅能处理 Servlet 原生的 Request/Response 对象;
  2. invoke 方法中必须调用 getNext().invoke(request, response),否则请求会中断,无法传递到后续容器;
  3. 异常处理必须完善,Valve 中抛出异常会导致请求直接失败,影响全局服务;
  4. 避免在 Valve 中执行耗时操作,否则会严重影响 Tomcat 整体性能。

12.2 自定义类加载器

Tomcat 的核心优势之一是灵活的类加载器架构,支持自定义类加载器,实现类隔离、加密类加载、热加载、非标准路径类加载等高级需求。

12.2.1 Tomcat 类加载器架构回顾

Tomcat 启动时会创建层级化的类加载器,默认架构如下(从上到下为父子关系):

plaintext

复制代码
Bootstrap ClassLoader(JVM 启动类加载器,加载JVM核心类库)
    ↓
Extension ClassLoader(JDK 扩展类加载器,加载jre/lib/ext类)
    ↓
System ClassLoader(应用类加载器,加载Tomcat bin目录下的启动类)
    ↓
Common ClassLoader(Tomcat 公共类加载器,加载lib目录下的类,所有应用共享)
    ↓
WebAppClassLoader(Web应用类加载器,每个应用一个,加载WEB-INF/classes和WEB-INF/lib)
12.2.2 自定义类加载器的使用场景
  1. 类加密保护:对业务 class 文件进行加密,自定义类加载器在加载时解密,防止代码反编译;
  2. 非标准路径类加载:从指定目录、网络、数据库等非标准位置加载类文件和 jar 包;
  3. 高级类隔离:实现更细粒度的类隔离,比如同一个应用内不同模块的类隔离;
  4. 热加载 / 热部署:自定义类加载器实现类的动态卸载与重新加载,无需重启 Tomcat;
  5. 类加载过程拦截:在类加载时执行字节码修改、类版本校验、权限控制等操作。
12.2.3 自定义类加载器开发与配置

Tomcat 中自定义类加载器,推荐继承 Tomcat 内置的 WebappClassLoader,适配 Tomcat 的类加载机制,避免破坏原有类隔离特性。

开发步骤
  1. 引入 Tomcat 依赖,同 12.1.3 节;

  2. 继承 WebappClassLoader,重写类加载相关方法,示例为加密类加载器:

    java

    运行

    复制代码
    import org.apache.catalina.loader.WebappClassLoader;
    import org.apache.catalina.loader.WebappClassLoaderBase;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /**
     * 自定义加密类加载器,解密加密的class文件后加载
     */
    public class EncryptClassLoader extends WebappClassLoader {
    
        // 加密密钥,与加密工具类保持一致
        private static final byte ENCRYPT_KEY = 0x0F;
    
        // 必须提供无参构造器
        public EncryptClassLoader() {
            super();
        }
    
        // 必须提供带父加载器的构造器
        public EncryptClassLoader(ClassLoader parent) {
            super(parent);
        }
    
        /**
         * 重写findClass方法,实现自定义类加载
         */
        @Override
        public Class<?> findClass(String className) throws ClassNotFoundException {
            // 1. 转换类全限定名为文件路径
            String classPath = className.replace('.', '/') + ".class";
            byte[] classBytes = null;
    
            try {
                // 2. 读取加密的class文件字节码
                classBytes = loadEncryptedClassBytes(classPath);
                // 3. 解密字节码
                classBytes = decrypt(classBytes);
            } catch (IOException e) {
                // 读取失败,委托父类加载
                return super.findClass(className);
            }
    
            // 4. 定义类,将字节码转换为Class对象
            return defineClass(className, classBytes, 0, classBytes.length);
        }
    
        /**
         * 读取加密的class文件字节码
         */
        private byte[] loadEncryptedClassBytes(String classPath) throws IOException {
            File classFile = new File(getResourcePaths().iterator().next() + classPath);
            try (FileInputStream fis = new FileInputStream(classFile);
                 ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = fis.read(buffer)) != -1) {
                    bos.write(buffer, 0, len);
                }
                return bos.toByteArray();
            }
        }
    
        /**
         * 简单异或解密,生产环境可使用AES等非对称加密
         */
        private byte[] decrypt(byte[] data) {
            byte[] result = new byte[data.length];
            for (int i = 0; i < data.length; i++) {
                result[i] = (byte) (data[i] ^ ENCRYPT_KEY);
            }
            return result;
        }
    }
  3. 编译打包,生成 jar 包。

部署与配置
  1. 将 jar 包放入 Tomcat 的 lib 目录(类加载器本身必须由 Common 类加载器加载);

  2. 配置自定义类加载器到 Web 应用,有两种方式:

    • 方式一:全局配置,修改 conf/context.xml,对所有应用生效:

      xml

      复制代码
      <Context>
          <!-- 其他默认配置 -->
          <Loader className="com.tomcat.custom.EncryptClassLoader"
                  delegate="false" />
      </Context>
    • 方式二:单应用配置,修改应用的 META-INF/context.xml,仅对当前应用生效:

      xml

      复制代码
      <?xml version="1.0" encoding="UTF-8"?>
      <Context>
          <Loader className="com.tomcat.custom.EncryptClassLoader"
                  delegate="false" />
      </Context>
  3. 重启 Tomcat,应用启动时会使用自定义类加载器加载类。

12.2.4 自定义类加载器注意事项
  1. 必须遵循 Tomcat 的类加载机制,核心类(java.、javax.、org.apache.catalina.*)必须委托父加载器加载,不可自行加载,否则会导致安全异常和类型转换异常;
  2. 类加载器必须提供无参构造器和带 ClassLoader parent 参数的构造器,否则 Tomcat 无法实例化;
  3. 自定义类加载器会增加类泄漏的风险,热加载场景下必须确保类加载器的生命周期管理,避免旧的类加载器无法被 GC 回收,导致元空间溢出;
  4. 加密类加载器场景下,JDK 核心类、Tomcat 容器类不可加密,仅可加密业务类;
  5. 生产环境需做好异常兜底,自定义类加载失败时,必须委托父类加载器加载,避免应用启动失败。

12.3 嵌入式 Tomcat

嵌入式 Tomcat(Embedded Tomcat)是将 Tomcat 核心组件以 jar 包的形式引入,通过代码实例化、配置、启动 Tomcat 容器,无需单独安装 Tomcat 服务器,是 SpringBoot、SpringCloud 等微服务框架的底层核心组件。

12.3.1 嵌入式 Tomcat 的核心优势
  1. 轻量化部署:无需单独安装 Tomcat,应用与容器打包为一个可执行 jar 包,一键启动;
  2. 极致定制化:通过代码灵活配置连接器、容器、资源、组件,无需修改 XML 配置文件;
  3. 易于集成:完美适配微服务架构、单元测试、云原生部署场景;
  4. 版本统一:避免开发、测试、生产环境 Tomcat 版本不一致导致的兼容性问题;
  5. 快速启动:仅加载必要的核心组件,启动速度远快于独立安装的 Tomcat。
12.3.2 嵌入式 Tomcat 快速入门
环境准备

Maven 引入嵌入式 Tomcat 核心依赖,以 Tomcat 9 为例(Tomcat 10+ 适配 Jakarta EE,依赖包名不同):

xml

复制代码
<dependencies>
    <!-- 嵌入式Tomcat核心依赖 -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>9.0.85</version>
    </dependency>
    <!-- Servlet API依赖 -->
    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-servlet-api</artifactId>
        <version>9.0.85</version>
        <scope>provided</scope>
    </dependency>
    <!-- JSP支持,无需JSP可省略 -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <version>9.0.85</version>
    </dependency>
    <!-- WebSocket支持,无需可省略 -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-websocket</artifactId>
        <version>9.0.85</version>
    </dependency>
</dependencies>
最简启动示例

通过代码实例化 Tomcat 容器,配置端口、上下文路径,启动服务:

java

运行

复制代码
import org.apache.catalina.startup.Tomcat;
import java.io.File;

public class EmbeddedTomcatDemo {
    public static void main(String[] args) throws Exception {
        // 1. 创建Tomcat实例
        Tomcat tomcat = new Tomcat();

        // 2. 配置核心参数
        tomcat.setPort(8080); // 配置HTTP端口
        tomcat.setBaseDir("tomcat-temp"); // 配置Tomcat工作目录,存放临时文件、日志

        // 3. 配置Web应用上下文
        String contextPath = "/demo"; // 上下文路径,根路径为""
        String docBase = new File("src/main/webapp").getAbsolutePath(); // Web资源根目录
        tomcat.addWebapp(contextPath, docBase);

        // 4. 可选:添加自定义Servlet
        Tomcat.addServlet(contextPath, "helloServlet", new HelloServlet());
        tomcat.getServletContext(contextPath).addServletMappingDecoded("/hello", "helloServlet");

        // 5. 启动Tomcat
        tomcat.start();
        System.out.println("嵌入式Tomcat启动成功,访问地址:http://localhost:8080/demo/hello");

        // 6. 阻塞主线程,保持服务运行
        tomcat.getServer().await();
    }
}
自定义 Servlet 示例

java

运行

复制代码
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.write("<h1>Hello Embedded Tomcat!</h1>");
        out.flush();
    }
}
12.3.3 核心配置与高级定制
  1. 连接器定制自定义 HTTP 连接器,配置线程池、超时、长连接等参数:

    java

    运行

    复制代码
    import org.apache.catalina.connector.Connector;
    import org.apache.coyote.http11.Http11Nio2Protocol;
    
    // 替换默认连接器
    Connector connector = new Connector("org.apache.coyote.http11.Http11Nio2Protocol");
    connector.setPort(8080);
    Http11Nio2Protocol protocol = (Http11Nio2Protocol) connector.getProtocolHandler();
    // 配置线程池
    protocol.setMaxThreads(400);
    protocol.setMinSpareThreads(50);
    // 配置超时
    protocol.setConnectionTimeout(6000);
    protocol.setKeepAliveTimeout(60000);
    // 禁用DNS反向解析
    connector.setEnableLookups(false);
    // 设置连接器到Tomcat
    tomcat.setConnector(connector);
  2. Engine/Host 定制自定义虚拟主机、引擎配置,添加 Valve 组件:

    java

    运行

    复制代码
    // 获取Engine
    org.apache.catalina.Engine engine = tomcat.getEngine();
    engine.setDefaultHost("localhost");
    
    // 获取Host
    org.apache.catalina.Host host = tomcat.getHost();
    host.setAutoDeploy(false); // 关闭自动部署
    host.setAppBase(docBase);
    
    // 添加自定义Valve
    host.addValve(new RequestCostValve());
  3. 关闭热部署与自动部署生产环境建议关闭,提升性能与稳定性:

    java

    运行

    复制代码
    org.apache.catalina.Context context = tomcat.addWebapp(contextPath, docBase);
    context.setReloadable(false); // 关闭类热加载
    host.setAutoDeploy(false); // 关闭自动部署
    host.setDeployOnStartup(true); // 启动时部署
  4. 自定义类加载器为 Web 应用配置自定义类加载器,见 12.2 节:

    java

    运行

    复制代码
    context.setLoader(new EncryptClassLoader());
12.3.4 SpringBoot 中的嵌入式 Tomcat

SpringBoot 默认使用嵌入式 Tomcat 作为 Servlet 容器,可通过配置文件和代码实现深度定制:

  1. application.yml 配置

    yaml

    复制代码
    server:
      port: 8080
      servlet:
        context-path: /demo
      tomcat:
        # 线程池配置
        threads:
          max: 400
          min-spare: 50
        # 连接配置
        connection-timeout: 6000
        keep-alive-timeout: 60s
        max-keep-alive-requests: 1000
        # 缓冲区配置
        max-http-form-post-size: 10MB
        max-swallow-size: 10MB
        # 访问日志配置
        accesslog:
          enabled: true
          directory: logs
          pattern: "%h %l %u %t \"%r\" %s %b %D"
  2. 代码定制化 实现 WebServerFactoryCustomizer 接口,深度定制 Tomcat 配置:

    java

    运行

    复制代码
    import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
    import org.springframework.boot.web.server.WebServerFactoryCustomizer;
    import org.springframework.stereotype.Component;
    
    @Component
    public class TomcatCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    
        @Override
        public void customize(TomcatServletWebServerFactory factory) {
            // 添加自定义Valve
            factory.addContextValves(new RequestCostValve());
            // 自定义连接器
            factory.addConnectorCustomizers(connector -> {
                connector.setEnableLookups(false);
                connector.setXpoweredBy(false);
            });
            // 自定义上下文
            factory.addContextCustomizers(context -> {
                context.setReloadable(false);
            });
        }
    }

12.4 Tomcat 源码编译与调试

阅读、编译、调试 Tomcat 源码,是深入理解 Tomcat 底层原理、实现二次开发的最佳方式,本节以 Tomcat 9 为例,讲解源码编译、环境搭建、断点调试的完整流程。

12.4.1 环境准备

表格

工具 版本要求 说明
JDK JDK 8+,Tomcat 9 推荐 JDK 8 Tomcat 10+ 要求 JDK 11+
Maven 3.6+ 依赖管理与构建
IDE IDEA/Eclipse 推荐 IDEA,对源码调试支持更好
Git 任意版本 拉取官方源码
12.4.2 源码获取
  1. 官方 Git 仓库:https://github.com/apache/tomcat.git

  2. 切换到稳定版本分支,以 9.0.85 为例: bash

    运行

    复制代码
    # 克隆仓库
    git clone https://github.com/apache/tomcat.git
    # 进入源码目录
    cd tomcat
    # 切换到稳定版本标签
    git checkout 9.0.85
  3. 也可直接从 Apache 官网下载源码压缩包:https://tomcat.apache.org/download-90.cgi,选择 Source Code Distributions 下载。

12.4.3 源码编译

Tomcat 官方使用 Ant 构建,也可通过 Maven 适配,推荐使用官方 Ant 方式,避免构建异常。

方式一:Ant 编译(官方推荐)
  1. 安装 Ant,配置 ANT_HOME 环境变量,执行 ant -version 验证;

  2. 复制源码根目录下的 build.properties.default 文件,重命名为 build.properties

  3. 编辑 build.properties,修改核心配置:

    properties

    复制代码
    # 配置JDK路径
    base.path=./build-lib
    # 跳过测试
    execute.test.skip=true
    # 配置编译版本
    javac.source=1.8
    javac.target=1.8
  4. 执行编译命令: bash

    运行

    复制代码
    # 构建完整发行包
    ant release
    # 仅编译源码,不打包
    ant compile
  5. 编译成功后,会在源码根目录生成 output 文件夹,包含编译后的 class 文件、可运行的 Tomcat 发行包。

方式二:IDEA 中 Maven 编译
  1. 在源码根目录创建 pom.xml 文件,添加 Maven 依赖配置(适配 Tomcat 9 版本);
  2. 打开 IDEA,导入源码根目录为 Maven 项目;
  3. IDEA 自动下载依赖,执行 mvn clean compile 命令完成编译。
12.4.4 IDEA 源码导入与调试环境搭建
  1. 打开 IDEA,选择 Open,导入编译后的 Tomcat 源码根目录;
  2. 配置项目 SDK:
    • 进入 File -> Project Structure -> Project,配置 Project SDK 为 JDK 8,Project language level 为 8;
  3. 标记源码目录:
    • 进入 File -> Project Structure -> Modules,将 java 目录标记为 Sources 源码根目录;
    • test 目录标记为 Test Sources 测试源码目录;
  4. 配置启动类:Tomcat 的入口类为 org.apache.catalina.startup.Bootstrap,配置启动项:
    1. 进入 Run -> Edit Configurations,新建一个 Application 启动配置;

    2. 配置 Main class 为 org.apache.catalina.startup.Bootstrap

    3. 配置 VM options,设置 Catalina 基础目录: plaintext

      复制代码
      -Dcatalina.home=./output/build
      -Dcatalina.base=./output/build
      -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
      -Djava.util.logging.config.file=./output/build/conf/logging.properties
    4. 配置 Working directory 为源码根目录;

    5. 勾选 Use classpath of module,选择当前项目模块;

  5. 启动调试:点击 Debug 按钮,启动 Bootstrap 类,控制台输出 Tomcat 启动日志,启动成功后,访问 http://localhost:8080 即可看到 Tomcat 首页,说明环境搭建成功。
12.4.5 核心断点调试入口

掌握核心断点位置,可快速理解 Tomcat 启动、请求处理的全流程:

表格

断点位置 核心作用
Bootstrap.main() Tomcat 启动入口,调试启动全流程
Catalina.load() 解析 server.xml 配置文件,初始化容器组件
Catalina.start() 启动 Server、Service、Engine、Host、Context、Wrapper 全层级容器
StandardContext.startInternal() Web 应用上下文启动,加载 web.xml、初始化 Servlet、Listener、Filter
Http11Processor.service() HTTP 请求解析入口,调试请求解析流程
CoyoteAdapter.service() 连接器到容器的适配器,请求从 Coyote 连接器传递到 Catalina 容器的入口
StandardPipeline-Valve.invoke() 阀门链执行入口,调试请求经过 Valve 的全流程
StandardWrapperValve.invoke() Servlet 调用入口,调试 Servlet 初始化、请求处理流程
12.4.6 常见编译与调试问题解决
  1. 依赖缺失报错 :Ant 编译时自动下载依赖,若下载失败,可手动下载依赖包放入 build-lib 目录,或配置国内镜像源;
  2. 类找不到报错:检查源码目录是否正确标记为 Sources,JDK 版本是否匹配,是否完成编译;
  3. 启动时 conf 目录找不到:检查 VM options 中的 catalina.home 路径是否正确,必须指向编译后包含 conf、webapps 目录的路径;
  4. webapps 下应用无法加载:检查 Host 的 appBase 路径配置,确保路径正确,权限正常;
  5. 源码与字节码不匹配:重新执行编译命令,确保源码修改后完成重新编译,清空 IDEA 缓存。

附录

一、常用命令速查

1. Tomcat 核心启停命令(Linux)

表格

命令 作用 适用场景
./bin/startup.sh 后台启动 Tomcat 生产环境常规启动
./bin/shutdown.sh 优雅关闭 Tomcat,等待请求处理完成 常规停止服务
./bin/shutdown.sh -force 强制关闭 Tomcat,超时后直接 kill 进程 优雅关闭失败时使用
./bin/catalina.sh run 前台启动 Tomcat,日志输出到终端 开发调试、快速定位启动问题
./bin/catalina.sh start 等同于 startup.sh,后台启动 -
./bin/catalina.sh stop 等同于 shutdown.sh,优雅关闭 -
./bin/catalina.sh debug 调试模式启动,开启远程调试端口 8000 源码调试、远程问题定位
./bin/catalina.sh configtest 校验 server.xml 等配置文件语法,不启动服务 修改配置后,先校验再重启,避免启动失败
./bin/version.sh 查看 Tomcat 版本、JDK 版本、操作系统信息 版本兼容性排查
2. 进程与状态查看命令

表格

命令 作用
`ps -ef grep tomcat` 查看 Tomcat 进程 PID、启动参数、运行用户
jps -l 快速查看 Java 进程 PID 与主类名,定位 Tomcat 进程
`netstat -tulnp grep java` 查看 Tomcat 占用的端口、连接监听状态
`ss -tulnp grep java` 更高效的端口与连接查看命令,替代 netstat
3. 日志查看命令

表格

命令 作用
tail -f logs/catalina.out 实时查看 Tomcat 运行日志,最常用
tail -n 500 logs/catalina.out 查看日志最后 500 行,定位最近报错
grep 'Exception' logs/catalina.out 筛选日志中的异常信息
grep 'OutOfMemoryError' logs/catalina.out 排查 OOM 相关报错
less logs/catalina.out 大日志文件分页查看,支持上下翻页、搜索
4. JVM 监控与故障排查命令

表格

命令 作用
jstat -gc 进程PID 1000 每秒输出一次 GC 详情,实时监控 GC 状态
jstat -gcutil 进程PID 查看 JVM 各内存区域占用率
jstack -l 进程PID > thread_dump.log 生成线程快照,输出到文件,排查死锁、线程阻塞
jmap -dump:format=b,file=heap_dump.hprof 进程PID 生成堆内存快照,排查 OOM、内存泄漏
`jmap -histo 进程 PID head -20` 查看堆内存中 TOP20 占用的对象类型

二、配置文件模板

1. server.xml 生产环境核心模板(精简版,带注释)

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="自定义安全密钥">
  <!-- 监听器配置 -->
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <!-- 全局资源配置 -->
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <!-- 服务配置 -->
  <Service name="Catalina">
    <!-- HTTP连接器核心配置,生产环境优化版 -->
    <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               maxThreads="400"
               minSpareThreads="50"
               acceptCount="200"
               maxConnections="8000"
               connectionTimeout="6000"
               maxKeepAliveRequests="1000"
               keepAliveTimeout="60000"
               enableLookups="false"
               xpoweredBy="false"
               server="Apache Tomcat"
               URIEncoding="UTF-8"
               relaxedPathChars="|{}[],%"
               relaxedQueryChars="|{}[],%" />

    <!-- 禁用AJP连接器,非集群反向代理场景无需开启 -->
    <!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->

    <!-- 引擎配置 -->
    <Engine name="Catalina" defaultHost="localhost">
      <!-- 集群配置,非集群场景可删除 -->
      <!-- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> -->

      <!-- 安全配置:全局访问控制Valve,生产环境按需配置 -->
      <!-- <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.0\.0\.1|192\.168\.\d{1,3}\.\d{1,3}" /> -->

      <!-- 错误页面配置,隐藏服务器信息 -->
      <Valve className="org.apache.catalina.valves.ErrorReportValve"
             showReport="false"
             showServerInfo="false" />

      <!-- 访问日志配置 -->
      <Valve className="org.apache.catalina.valves.AccessLogValve"
             directory="logs"
             prefix="localhost_access_log"
             suffix=".txt"
             pattern="%h %l %u %t &quot;%r&quot; %s %b %D &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot;"
             rotatable="true"
             maxDays="30" />

      <!-- 虚拟主机配置 -->
      <Host name="localhost" appBase="webapps"
            unpackWARs="true"
            autoDeploy="false"
            deployOnStartup="true">
        <!-- 主机级别的访问控制、Valve配置,按需添加 -->
      </Host>
    </Engine>
  </Service>
</Server>
2. context.xml 生产环境模板

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <!-- 关闭资源链接跟踪,避免内存泄漏 -->
  <WatchedResource>WEB-INF/web.xml</WatchedResource>
  <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
  <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

  <!-- 关闭热加载,生产环境提升性能 -->
  <Loader delegate="false" reloadable="false" />

  <!-- 禁用会话持久化,重启时不恢复会话 -->
  <Manager pathname="" />

  <!-- 数据库连接池配置示例,按需添加 -->
  <!--
  <Resource name="jdbc/DBPool"
            auth="Container"
            type="javax.sql.DataSource"
            driverClassName="com.mysql.cj.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"
            username="root"
            password="密码"
            maxTotal="100"
            maxIdle="20"
            maxWaitMillis="10000"
            testOnBorrow="true"
            validationQuery="SELECT 1" />
  -->
</Context>

三、性能参数参考值

1. JVM 参数参考值(基于 Linux 服务器)

表格

服务器配置 堆内存配置 元空间配置 GC 核心配置 适用场景
2 核 4G -Xms2g -Xmx2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 低流量测试环境、小型单体应用
4 核 8G -Xms4g -Xmx4g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError 生产环境中小型应用、并发量 100-300
8 核 16G -Xms8g -Xmx8g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/ 生产环境中大型应用、并发量 300-800
16 核 32G -Xms16g -Xmx16g -XX:MetaspaceSize=1g -XX:MaxMetaspaceSize=2g -XX:+UseZGC(JDK17+)/G1GC -XX:MaxGCPauseMillis=50 -XX:+HeapDumpOnOutOfMemoryError 高并发生产环境、并发量 800+

通用优化参数

bash

运行

复制代码
JAVA_OPTS="$JAVA_OPTS
-server
-Dfile.encoding=UTF-8
-Djava.security.egd=file:/dev/./urandom
-XX:+DisableExplicitGC
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=${catalina.base}/logs/
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:${catalina.base}/logs/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=100M"
2. Connector 连接器参数参考值

表格

参数 低并发(<100) 中并发(100-500) 高并发(500+) 说明
protocol Http11NioProtocol Http11Nio2Protocol Http11Nio2Protocol 优先使用 NIO2 非阻塞模型
maxThreads 200 400 800 最大工作线程数,不建议超过 1000
minSpareThreads 20 50 100 核心常驻线程数
acceptCount 100 200 500 等待队列长度,线程满时请求进入队列
maxConnections 2000 8000 20000 最大连接数,NIO 模式下远大于 maxThreads
connectionTimeout 10000 6000 3000 连接超时时间,单位 ms,高并发场景建议缩短
keepAliveTimeout 60000 60000 30000 长连接超时时间,单位 ms
maxKeepAliveRequests 100 1000 10000 单个长连接最大请求数

四、学习资源推荐

1. 官方文档(首选权威资源)
  • Apache Tomcat 官方文档:https://tomcat.apache.org包含各个版本的完整文档、配置指南、API 文档、最佳实践,是最权威的学习资料。
  • Tomcat 官方 Wiki:https://cwiki.apache.org/confluence/display/TOMCAT包含常见问题、性能优化、安全公告、架构设计文档。
2. 经典书籍
  • 《Tomcat 权威指南》:Tomcat 官方团队编写,全面覆盖 Tomcat 配置、部署、管理、安全,适合入门到进阶。
  • 《深入剖析 Tomcat》:深入讲解 Tomcat 架构设计、核心组件、源码实现,适合原理学习与二次开发。
  • 《Tomcat 内核设计与架构解析》:从源码角度拆解 Tomcat 核心实现,涵盖 I/O 模型、类加载器、容器设计等核心内容。
3. 优质开源项目与专栏
  • Tomcat 源码仓库:https://github.com/apache/tomcat
  • 芋道源码 Tomcat 源码解析:https://www.iocoder.cn/Tomcat/,通俗易懂的源码分析教程。
  • 极客时间《深入拆解 Tomcat & Jetty》:系统讲解 Tomcat 核心原理、架构设计、性能优化。
4. 社区与安全资源
  • Apache Tomcat 邮件列表:官方用户与开发邮件列表,可获取最新动态、问题解答。
  • CVE 安全公告:https://tomcat.apache.org/security.html,及时获取 Tomcat 安全漏洞与修复方案。
  • Stack Overflow Tomcat 专区:https://stackoverflow.com/questions/tagged/tomcat,全球开发者问题解答社区。
  1. 存、线程、GC、MBean 指标,支持简单的 MBean 操作
相关推荐
-许平安-38 分钟前
MCP项目笔记六(PluginsLoader)
c++·笔记·raii·plugin system
开源盛世!!41 分钟前
3.26-3.27学习笔记
笔记·学习
智者知已应修善业1 小时前
【文氏电桥振荡电路】2022-8-25
驱动开发·经验分享·笔记·硬件架构·硬件工程
小趴菜_自动驾驶搬砖人1 小时前
数据校验学习笔记 ———— 模逆运算
笔记
大连好光景1 小时前
软件测试笔记(1)
笔记·功能测试·测试工具
程序员侠客行2 小时前
Tomcat 从陌生到熟悉
java·tomcat·web
Hammer_Hans2 小时前
DFT笔记33
笔记
宵时待雨2 小时前
C++笔记归纳17:哈希
数据结构·c++·笔记·算法·哈希算法
山川行2 小时前
Python快速闯关8:内置函数
java·开发语言·前端·笔记·python·学习·visual studio
鸟电波3 小时前
硬件笔记——立创EDA的模块复用
笔记