基于本文回答
0
评论

Tomcat 是如何管理 Session 的?

知识点图片

Tomcat 管理 Session 的机制是一个经典且高效的过程,主要涉及会话的创建、ID生成与传递、存储结构、生命周期管理以及持久化

核心组件是 Tomcat 容器中的 Manager 接口及其实现类(主要是 StandardManager)。

以下是 Tomcat 管理 Session 的详细内部机制:


1. 核心架构组件

在 Tomcat 的架构中,Session 管理属于 Context 容器(即 Web 应用)的一部分。

  • Manager (管理器): 负责管理所有的 Session 对象。它负责创建、查找、更新、销毁 Session。
    • 默认实现是 org.apache.catalina.session.StandardManager
  • Session (会话对象): 对应 javax.servlet.http.HttpSession 接口,Tomcat 内部的实现是 org.apache.catalina.session.StandardSession

2. Session 的创建与 ID 生成

当用户代码调用 request.getSession()request.getSession(true) 时,流程如下:

  1. 检查是否存在: Tomcat 首先检查 HTTP 请求中是否包含 Session ID(通常在 Cookie 或 URL 中)。
  2. 查找: 如果有 ID,Manager 会尝试在内存中查找对应的 Session 对象。如果找到且未过期,直接返回。
  3. 创建: 如果没有 ID,或者 ID 对应的 Session 已失效,Manager 会创建一个新的 StandardSession 对象。
  4. 生成 Session ID:
    • Tomcat 使用 SessionIdGenerator 生成一个唯一的字符串(通常是 32 位十六进制字符)。
    • 为了安全,它使用 SecureRandom 类来保证 ID 的随机性,防止被预测(Session 劫持)。
    • 生成的 ID 就是我们常见的 JSESSIONID

3. Session ID 的传递机制 (Tracking)

服务器创建 Session 后,必须告诉客户端这个 ID,以便后续请求能识别身份。Tomcat 支持两种方式:

  1. Cookie (默认 & 首选):
    • Tomcat 会在 HTTP 响应头中添加 Set-Cookie: JSESSIONID=xxxxxx; Path=/; HttpOnly
    • 浏览器收到后保存,后续请求会自动带上 Cookie: JSESSIONID=xxxxxx
  2. URL Rewriting (URL 重写):
    • 如果客户端禁用了 Cookie,Tomcat 支持将 ID 拼接到 URL 后面,格式如:http://example.com/index.jsp;jsessionid=xxxxxx
    • 这需要开发者在代码中使用 response.encodeURL() 来处理链接。

4. 内存存储结构

StandardManager 将所有的 Session 对象存储在 JVM 的堆内存中。

  • 数据结构: 内部维护了一个 ConcurrentHashMap<String, Session>
    • Key: Session ID。
    • Value: Session 对象实例。
  • 并发控制: 由于是 ConcurrentHashMap,它支持高并发的读写操作。

5. 生命周期与过期处理

Session 不能永久存在,否则会撑爆内存。Tomcat 通过后台线程进行清理:

  • 后台线程: Tomcat 有一个 ContainerBackgroundProcessor 线程,定期(默认每 10 秒)调用 Manager.backgroundProcess()
  • 检查逻辑:
    1. 遍历 Map 中的 Session 对象。
    2. 检查 isValid()
    3. 计算:当前时间 - 最后访问时间 (LastAccessedTime)
    4. 如果差值大于 MaxInactiveInterval(默认 30 分钟,可在 web.xml 配置),则判定为过期。
  • 销毁:
    1. 调用 session.expire()
    2. 触发 HttpSessionListener.sessionDestroyed() 监听器。
    3. 从 Map 中移除该对象,释放内存。

6. 持久化 (Persistence) - 钝化与活化

为了防止 Tomcat 重启导致用户掉线,或者为了节省内存,Tomcat 提供了 Session 的持久化机制。

A. StandardManager (默认行为 - 重启恢复)

当 Tomcat 正常关闭(Shutdown)或重启时:

  1. 序列化 (钝化): StandardManager 会将内存中所有有效的 Session 对象序列化到一个文件 SESSIONS.ser 中(通常位于 work/Catalina/localhost/你的应用名/ 目录下)。
  2. 反序列化 (活化): 当 Tomcat 再次启动时,会读取该文件,将 Session 恢复到内存中。
    • 注意: 放入 Session 中的对象必须实现 java.io.Serializable 接口,否则无法持久化。

B. PersistentManager (高级配置 - 内存置换)

如果配置了 PersistentManager,Tomcat 可以将长期不活跃但未过期的 Session 移出内存。

  • Store: 可以配置保存到文件系统 (FileStore) 或数据库 (JDBCStore)。
  • 策略: 当内存中 Session 数量超过阈值,或某个 Session 闲置超过一定时间(maxIdleSwap),将其“钝化”到硬盘/数据库,腾出内存。当该 Session 再次被访问时,再将其“活化”回内存。

7. 集群环境下的 Session 管理 (分布式)

在多台 Tomcat 组成的集群中,默认的 StandardManager 无法共享 Session。Tomcat 提供了以下方案:

  1. Session 复制 (DeltaManager):
    • 利用 TCP 组播,将一台 Tomcat 上的 Session 变更复制到集群中所有其他节点。
    • 缺点:网络流量大,不适合大规模集群。
  2. BackupManager:
    • Session 只复制到一个备份节点,而不是所有节点。
  3. 第三方存储 (主流方案):
    • 实际上,现代架构很少使用 Tomcat 自带的集群 Session 管理。
    • 通常使用 Spring Session + Redis。Tomcat 此时只负责处理请求,Session 数据实际存储在外部的 Redis 中,实现了无状态化。

总结

Tomcat 管理 Session 的流程可以概括为:

  1. 生成安全的 ID。
  2. 通过 Cookie 交换 ID。
  3. 使用 ConcurrentHashMap 在内存中存储。
  4. 通过后台线程定期清理过期会话。
  5. 通过序列化文件处理重启时的数据保留。
右滑查看面试常问