1. 课程内容介绍
本专题围绕 Tomcat 展开,内容涵盖基础概念、整体架构、核心组件、服务器配置、JVM 调优、集群部署、安全加固以及 WebSocket 实战案例。课程从源码层面剖析 Tomcat 的启动流程、请求处理流程和 Jasper 引擎编译原理,帮助读者深入理解 Tomcat 的内部工作机制,并掌握生产环境下的配置与调优方法。
2. Tomcat 基础
2.1 Web 相关概念
Web 开发中常见的概念包括 HTTP 协议、Web 服务器、Servlet 容器等。HTTP 是浏览器与服务器之间通信的协议,Web 服务器负责接收请求并返回静态资源,而 Servlet 容器则负责加载和管理 Servlet,处理动态请求。Tomcat 既是一个 Web 服务器,也是一个 Servlet 容器。
2.2 常见的 Web 服务器软件
常见的 Web 服务器软件包括 Apache HTTP Server、Nginx、IIS 以及 Tomcat。其中 Apache 和 Nginx 主要处理静态资源和高并发转发,Tomcat 则专注于 Java Servlet 和 JSP 的动态处理。在实际项目中,常使用 Nginx 作为反向代理,将动态请求转发给 Tomcat。
2.3 Tomcat 安装及目录结构
Tomcat 的安装非常简单,只需下载对应版本的压缩包并解压即可。解压后的目录结构如下:
- bin:存放启动和关闭脚本,如 startup.sh、shutdown.sh。
- conf:存放配置文件,如 server.xml、web.xml。
- lib:存放 Tomcat 运行所需的 jar 包。
- logs:存放运行日志。
- webapps:存放部署的 Web 应用。
- work:存放 JSP 编译后的 class 文件。
2.4 Tomcat 源码部署运行
为了深入理解 Tomcat 的源码,可以将 Tomcat 源码导入 IDE 进行调试。首先从官网下载源码包,然后使用 Maven 构建项目。构建完成后,运行 org.apache.catalina.startup.Bootstrap 类的 main 方法即可启动 Tomcat。通过源码调试,可以清晰地看到 Tomcat 的启动流程和请求处理流程。
3. Tomcat 架构
3.1 HTTP 工作流程
一次完整的 HTTP 请求处理流程如下:浏览器发起请求,经过网络传输到达 Tomcat 的 Connector,Connector 将请求解析为 Request 对象,然后交给 Container 处理。Container 中的 Engine、Host、Context 逐级匹配,最终定位到具体的 Servlet。Servlet 处理完成后,将 Response 返回给 Connector,再由 Connector 将响应写回浏览器。
3.2 Tomcat 整体架构
Tomcat 的整体架构由 Connector 和 Container 两大部分组成。Connector 负责处理网络连接和协议解析,Container 负责处理 Servlet 请求。一个 Tomcat 实例可以配置多个 Connector(如 HTTP、HTTPS、AJP),它们共享同一个 Container。Container 采用分层结构,从上到下依次为 Engine、Host、Context、Wrapper。
3.3 Coyote 连接器架构
Coyote 是 Tomcat 的连接器框架,负责处理底层网络通信。它支持多种协议(HTTP/1.1、HTTP/2、AJP)和多种 IO 模型(BIO、NIO、NIO2、APR)。Coyote 的核心组件包括 Endpoint、Processor 和 Adapter。Endpoint 负责监听端口和接收连接,Processor 负责解析协议,Adapter 则将请求适配给 Container。
3.4 Coyote 连接器组件
Coyote 连接器的主要组件如下:
- Endpoint:负责底层 Socket 的监听和读写,提供 NIO 和 BIO 两种实现。
- Processor:负责将字节流解析为 HttpServletRequest 对象。
- Adapter:将 Processor 解析出的请求交给 Container 处理,是连接器与容器之间的桥梁。
- ProtocolHandler:封装了 Endpoint 和 Processor,对外提供统一的协议处理入口。
3.5 Catalina 容器结构
Catalina 是 Tomcat 的 Servlet 容器实现,其核心是 Container 接口。Container 有四种实现:Engine、Host、Context、Wrapper,它们之间是父子关系。Engine 代表整个 Catalina 引擎,Host 代表一个虚拟主机,Context 代表一个 Web 应用,Wrapper 代表一个 Servlet。每个 Container 都包含 Pipeline 和 Valve,用于处理请求。
3.6 启动流程
Tomcat 的启动流程从 Bootstrap 的 main 方法开始,主要步骤如下:
- 初始化类加载器,加载 catalina.jar 等核心类。
- 创建 Catalina 实例,并加载 server.xml 配置文件。
- 根据配置创建 StandardServer、StandardService、Connector 和 Engine 等组件。
- 调用各组件的 init 和 start 方法,完成初始化并启动。
- 注册关闭钩子,等待关闭命令。
3.7 启动流程 - 涉及组件介绍
启动过程中涉及的核心组件包括:
- Bootstrap:Tomcat 的入口类,负责创建 Catalina 并启动。
- Catalina:负责解析 server.xml,管理 Server 的生命周期。
- StandardServer:代表整个 Tomcat 服务器,管理多个 Service。
- StandardService:包含一个 Engine 和多个 Connector。
- StandardEngine:代表 Servlet 引擎,管理多个 Host。
3.8 启动流程 - 源码跟踪
通过源码跟踪,可以更清晰地理解启动流程。以下是 Bootstrap 启动的核心代码逻辑:
java
public class Bootstrap {
public static void main(String[] args) {
// 1. 初始化类加载器
// 创建 Tomcat 自定义的类加载器体系,用于加载 catalina.jar 等核心类
initClassLoaders();
// 2. 创建 Catalina 实例
// Catalina 是 Tomcat 的核心容器,负责解析配置和管理生命周期
Catalina catalina = new Catalina();
// 3. 加载 server.xml 配置
// 解析 conf/server.xml,根据配置创建 Server、Service、Connector、Engine 等组件
catalina.load();
// 4. 启动 Tomcat
// 调用各组件的 start 方法,完成初始化并开始对外提供服务
catalina.start();
// 5. 注册关闭钩子
// 当 JVM 收到关闭信号时,自动调用 catalina.stop() 优雅关闭 Tomcat
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
catalina.stop();
}));
// 6. 等待关闭
// 主线程阻塞等待,直到收到 SHUTDOWN 命令或 JVM 退出
catalina.await();
}
}
3.9 请求处理流程
请求处理流程是 Tomcat 的核心机制。当请求到达 Connector 后,经过以下步骤:
- Endpoint 接收 Socket 连接,并将连接交给 Processor。
- Processor 解析 HTTP 请求,生成 Request 和 Response 对象。
- Adapter 将 Request 和 Response 交给 Container。
- Engine 的 Pipeline 依次执行 Valve,最终将请求路由到对应的 Host。
- Host 再路由到 Context,Context 再路由到具体的 Wrapper(Servlet)。
- Servlet 执行 service 方法,生成响应并返回。
3.10 请求处理流程 - 源码跟踪
以下是请求处理的核心代码逻辑,展示了 Connector 如何将请求交给 Container:
java
public class CoyoteAdapter implements Adapter {
@Override
public void service(Request request, Response response) {
// 1. 将 Coyote 请求转换为 Catalina 请求
// 从 Request 的 Note 中取出之前由 Connector 存入的 Catalina Request 对象
org.apache.catalina.connector.Request catalinaRequest =
(org.apache.catalina.connector.Request) request.getNote(
ADAPTER_NOTES);
// 2. 获取 Container 并调用其 Pipeline
// 通过 Request 反向拿到 Connector,再拿到 Service 和 Engine
Connector connector = catalinaRequest.getConnector();
Service service = connector.getService();
Engine engine = service.getContainer();
// 3. 调用 Engine 的 Pipeline 处理请求
// Pipeline 中的 Valve 链会依次执行,最终把请求路由到对应的 Servlet
engine.getPipeline().getFirst().invoke(
catalinaRequest, catalinaResponse);
}
}
4. Jasper 引擎
4.1 介绍
Jasper 是 Tomcat 的 JSP 引擎,负责将 JSP 文件编译为 Servlet 源码,再编译为 class 文件。JSP 本质上是一个 Servlet,Jasper 的作用就是将 JSP 中的 HTML 和 Java 代码混合内容转换为纯 Java 代码。
4.2 编译方式 - 流程源码
Jasper 的编译流程如下:
- 当 JSP 文件首次被请求时,Jasper 会检查 JSP 文件是否被修改过。
- 如果 JSP 文件不存在对应的 class 文件,或者 JSP 文件被修改过,则触发编译。
- Jasper 将 JSP 文件解析为 AST(抽象语法树)。
- 根据 AST 生成 Java 源码,写入 work 目录。
- 使用 javac 将 Java 源码编译为 class 文件。
- 加载 class 文件,创建 Servlet 实例并执行。
4.3 编译原理
Jasper 编译的核心是 JspServlet。当请求到达时,JspServlet 会调用 JspCompilationContext 的 compile 方法进行编译。编译过程中,Parser 负责解析 JSP 文件,Generator 负责生成 Java 源码。生成的 Servlet 类继承自 HttpJspBase,其 _jspService 方法包含了 JSP 页面的所有逻辑。
5. 服务器配置
5.1 介绍(Server, Service)
server.xml 是 Tomcat 的核心配置文件。最顶层的元素是 Server,代表整个 Tomcat 实例。Server 内部包含多个 Service,每个 Service 包含一个 Engine 和多个 Connector。一个典型的配置如下:
xml
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" />
</Engine>
</Service>
</Server>
5.2 Executor
Executor 是 Tomcat 的线程池配置,用于管理处理请求的线程。通过配置 Executor,可以控制最大线程数、最小空闲线程数、队列长度等参数。示例配置如下:
xml
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="200"
minSpareThreads="25"
maxQueueSize="100" />
<Connector port="8080" protocol="HTTP/1.1"
executor="tomcatThreadPool" />
5.3 Connector
Connector 负责处理客户端连接。常用的配置参数包括 port(端口)、protocol(协议)、connectionTimeout(连接超时)、redirectPort(重定向端口)、maxThreads(最大线程数)等。对于 HTTPS,还需要配置 SSL 证书相关参数。
5.4 Engine, Host
Engine 是 Servlet 引擎,负责处理所有请求。Host 代表一个虚拟主机,通过域名区分。一个 Engine 可以包含多个 Host,每个 Host 可以包含多个 Context。配置示例:
xml
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context path="/myapp" docBase="myapp" />
</Host>
</Engine>
5.5 Context
Context 代表一个 Web 应用。每个 Context 对应一个应用目录或 WAR 包。Context 的配置可以放在 server.xml 中,也可以放在应用的 META-INF/context.xml 中。常用属性包括 path(访问路径)、docBase(应用目录)、reloadable(是否热部署)等。
6. Web 应用配置
6.1 今日内容
本节介绍 Web 应用的核心配置,包括 context-param、会话配置、Servlet/Listener/Filter 配置、欢迎页面和错误页面等。这些配置都写在 web.xml 文件中。
6.2 context-param
context-param 用于配置全局参数,可以在整个应用中通过 ServletContext 获取。配置示例:
xml
<context-param>
<param-name>globalConfig</param-name>
<param-value>config-value</param-value>
</context-param>
在 Java 代码中获取:
java
// 通过 ServletContext 获取 web.xml 中配置的全局参数
// getInitParameter 返回指定名称的 context-param 参数值
String value = getServletContext()
.getInitParameter("globalConfig");
6.3 会话配置 session-config
session-config 用于配置会话超时时间。单位是分钟,默认值为 30 分钟。配置示例:
xml
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
</session-config>
6.4 servlet-listener-filter
web.xml 中可以配置 Servlet、Listener 和 Filter。Servlet 用于处理请求,Listener 用于监听应用事件,Filter 用于拦截请求。配置示例:
xml
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.example.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.example.AppListener</listener-class>
</listener>
6.5 欢迎页面和错误页面
欢迎页面是访问应用根路径时默认显示的页面,错误页面用于处理 HTTP 错误码和异常。配置示例:
xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error/error.jsp</location>
</error-page>
7. Tomcat 管理配置
7.1 host-manager
host-manager 是 Tomcat 自带的虚拟主机管理应用,用于管理 Host。访问地址为 http://localhost:8080/host-manager。默认情况下,只有配置了 manager-gui 角色的用户才能访问。在 conf/tomcat-users.xml 中配置用户:
xml
<role rolename="admin-gui" />
<user username="admin" password="admin123"
roles="admin-gui" />
7.2 manager
manager 应用用于管理 Web 应用的部署、启动、停止和卸载。访问地址为 http://localhost:8080/manager。配置用户:
xml
<role rolename="manager-gui" />
<user username="tomcat" password="tomcat123"
roles="manager-gui" />
8. JVM 配置
8.1 内存参数配置
JVM 内存参数通过 CATALINA_OPTS 环境变量配置。常见参数包括:
- -Xms:初始堆内存大小。
- -Xmx:最大堆内存大小。
- -XX:PermSize:永久代初始大小(JDK 8 之前)。
- -XX:MaxPermSize:永久代最大大小(JDK 8 之前)。
- -XX:MetaspaceSize:元空间初始大小(JDK 8 之后)。
- -XX:MaxMetaspaceSize:元空间最大大小(JDK 8 之后)。
在 bin/catalina.sh 中配置示例:
bash
CATALINA_OPTS="-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"
9. Tomcat 集群
9.1 介绍及准备工作
Tomcat 集群用于提高系统的可用性和并发处理能力。集群中的每个节点运行相同的应用,通过负载均衡器分发请求。准备工作包括:准备多台服务器、安装 Tomcat、部署相同的应用、配置负载均衡器(如 Nginx)。
9.2 负载均衡策略
常见的负载均衡策略包括:
- 轮询:将请求依次分发到每个节点。
- 加权轮询:根据节点性能分配不同的权重。
- IP 哈希:根据客户端 IP 的哈希值分发请求,保证同一 IP 的请求始终到达同一节点。
- 最少连接:将请求分发到当前连接数最少的节点。
9.3 session 共享问题及方案
在集群环境中,用户的请求可能被分发到不同的节点,导致 Session 不一致。解决方案包括:
- Session 复制:节点之间同步 Session 数据。
- Session 粘滞:通过负载均衡策略,将同一用户的请求始终分发到同一节点。
- 集中式 Session 存储:将 Session 存储在 Redis 等外部存储中。
9.4 Session 复制
Session 复制通过配置 Cluster 实现。在 server.xml 的 Engine 中添加 Cluster 配置:
xml
<Engine name="Catalina" defaultHost="localhost">
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true" />
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000" />
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="5000" />
</Channel>
</Cluster>
</Engine>
9.5 SSO 解决 Session 共享问题
SSO(单点登录)是解决 Session 共享的另一种方案。用户只需登录一次,即可访问多个系统。常见的实现方式包括 CAS、OAuth2 等。在 Tomcat 中,可以通过配置 SSO Valve 实现同一虚拟主机下的单点登录:
xml
<Host name="localhost" appBase="webapps">
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
</Host>
10. Tomcat 安全
10.1 配置安全
Tomcat 安全配置包括:
- 修改默认端口和管理密码。
- 禁用不需要的 Connector 和协议。
- 配置访问控制,限制管理应用的访问 IP。
- 定期更新 Tomcat 版本,修复已知漏洞。
- 删除默认的示例应用(如 examples、docs)。
10.2 传输安全
传输安全主要通过 HTTPS 实现。HTTPS 使用 SSL/TLS 协议加密传输数据,防止数据被窃听和篡改。配置 HTTPS 需要生成 SSL 证书,并在 Connector 中配置。
10.3 HTTPS 协议配置
使用 keytool 生成自签名证书:
bash
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048
-validity 365 -keystore tomcat.keystore
在 server.xml 中配置 HTTPS Connector:
xml
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/tomcat.keystore"
type="RSA" />
</SSLHostConfig>
</Connector>
11. Tomcat 性能调优
11.1 性能测试
性能测试是调优的前提。常用的压测工具包括 Apache JMeter、ab(Apache Bench)等。通过压测可以获取吞吐量、响应时间、错误率等指标,为调优提供依据。
11.2 性能测试结果说明
性能测试结果通常包括以下指标:
- 吞吐量:单位时间内处理的请求数。
- 平均响应时间:所有请求的平均处理时间。
- 错误率:失败请求占总请求的比例。
- 并发数:同时处理的请求数量。
11.3 JVM 内存参数调优
JVM 内存调优的核心是合理设置堆内存大小。堆内存过小会导致频繁 GC,过大则可能导致内存溢出。建议将 -Xms 和 -Xmx 设置为相同值,避免堆大小动态调整带来的性能开销。示例:
bash
CATALINA_OPTS="-Xms1024m -Xmx1024m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
11.4 JVM 垃圾收集器介绍
常见的垃圾收集器包括:
- Serial GC:单线程收集器,适合单核 CPU 和小内存场景。
- Parallel GC:多线程收集器,适合多核 CPU 和高吞吐量场景。
- CMS GC:并发标记清除收集器,适合低延迟场景。
- G1 GC:分区式收集器,兼顾吞吐量和延迟,适合大内存场景。
11.5 垃圾收集器配置调整
在 JDK 8 中,可以通过以下参数指定垃圾收集器:
bash
# 使用 G1 收集器
CATALINA_OPTS="-XX:+UseG1GC -XX:MaxGCPauseMillis=200"
使用 Parallel 收集器
CATALINA_OPTS="-XX:+UseParallelGC -XX:ParallelGCThreads=4"
11.6 连接器配置调整
Connector 的配置对性能影响很大。关键参数包括 maxThreads(最大线程数)、acceptCount(等待队列长度)、connectionTimeout(连接超时)等。示例:
xml
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="400"
acceptCount="200"
connectionTimeout="20000"
minSpareThreads="50"
maxKeepAliveRequests="100" />
12. WebSocket
12.1 介绍
WebSocket 是一种全双工通信协议,允许服务器主动向客户端推送消息。与 HTTP 不同,WebSocket 在建立连接后,客户端和服务器之间可以随时互相发送消息,非常适合实时通信场景,如聊天室、在线游戏、实时通知等。
12.2 Tomcat 的支持
Tomcat 从 7.0.27 版本开始支持 WebSocket,从 8.0 版本开始支持 JSR-356(Java WebSocket 规范)。使用 Tomcat 开发 WebSocket 应用,只需实现 WebSocket 注解或继承相关类即可。
12.3 案例 - 需求及流程分析
本案例实现一个简单的在线聊天室。需求包括:用户登录、实时消息推送、在线用户列表、用户上下线通知。流程如下:
- 用户通过登录页面输入用户名登录。
- 登录成功后,建立 WebSocket 连接。
- 服务器维护在线用户列表,并广播用户上线消息。
- 用户发送消息,服务器将消息广播给所有在线用户。
- 用户关闭页面时,WebSocket 连接断开,服务器广播用户下线消息。
12.4 案例 - 准备工作
创建 Maven Web 项目,添加依赖:
xml
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
12.5 案例 - 登录功能
创建登录页面 login.jsp:
jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>聊天室登录</title>
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="username" />
<input type="submit" value="登录" />
</form>
</body>
</html>
创建登录 Servlet:
java
// 使用注解方式注册 Servlet,映射到 /login 路径
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
// 1. 获取表单提交的用户名参数
String username = req.getParameter("username");
// 2. 校验用户名是否为空(去除首尾空格后判断)
if (username != null && !username.trim().isEmpty()) {
// 3. 用户名合法:创建会话并保存用户名
HttpSession session = req.getSession();
session.setAttribute("username", username);
// 4. 重定向到聊天页面
resp.sendRedirect("chat.jsp");
} else {
// 5. 用户名非法:返回登录页重新输入
resp.sendRedirect("login.jsp");
}
}
}
12.6 案例 - OnOpen
创建 WebSocket 端点类 ChatEndpoint,使用 @ServerEndpoint 注解:
java
// 声明 WebSocket 端点,映射到 /chat 路径
@ServerEndpoint("/chat")
public class ChatEndpoint {
// 线程安全的在线用户会话集合,保存所有已连接的 Session
private static final Set<Session> clients =
Collections.synchronizedSet(new HashSet<>());
// 当客户端建立 WebSocket 连接时自动调用
@OnOpen
public void onOpen(Session session) {
// 1. 将新会话加入在线用户集合
clients.add(session);
// 2. 构造上线通知消息
String message = "用户 " + session.getId() + " 上线了";
// 3. 广播给所有在线用户
broadcast(message);
}
// 向所有在线用户广播消息
private void broadcast(String message) {
synchronized (clients) {
for (Session client : clients) {
try {
// 通过 BasicRemote 发送文本消息
client.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
12.7 案例 - OnOpen 测试
启动 Tomcat,访问登录页面,输入用户名登录后进入聊天页面。打开多个浏览器窗口,可以看到每个用户上线时,所有窗口都会收到上线通知。
12.8 案例 - OnMessage 分析
@OnMessage 注解的方法用于处理客户端发送的消息。在聊天室中,服务器收到消息后,需要将消息广播给所有在线用户。
12.9 案例 - OnMessage 功能实现
在 ChatEndpoint 中添加消息处理方法:
java
@OnMessage
public void onMessage(String message, Session session) {
String username = (String) session.getUserProperties()
.get("username");
String fullMessage = username + ":" + message;
broadcast(fullMessage);
}
12.10 案例 - OnMessage 功能测试
在聊天页面中输入消息并发送,所有在线用户的聊天窗口都会实时显示该消息。测试结果验证了 WebSocket 的全双工通信能力。
12.11 案例 - OnClose 及 OnError 介绍
@OnClose 注解的方法在连接关闭时调用,用于清理资源。@OnError 注解的方法在发生错误时调用。在聊天室中,当用户关闭页面时,需要从在线用户集合中移除该会话,并广播下线消息:
java
@OnClose
public void onClose(Session session) {
clients.remove(session);
String message = "用户 " + session.getId() + " 下线了";
broadcast(message);
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
clients.remove(session);
}
13. 总结
本专题系统性地介绍了 Tomcat 的核心知识,从基础概念、整体架构到源码级别的启动流程和请求处理流程,再到服务器配置、JVM 调优、集群部署、安全加固和 WebSocket 实战。通过本专题的学习,读者可以深入理解 Tomcat 的内部机制,掌握生产环境下的配置与调优方法,并具备使用 WebSocket 开发实时应用的能力。