You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Tomcat重载时RedissonSessionManager触发Redisson关闭

解决Tomcat上下文重载时Redisson客户端关闭的问题

核心原因

RedissonSessionManager默认将客户端生命周期与Tomcat Web上下文绑定,当上下文因重载销毁时,会触发Redisson客户端的关闭钩子,导致客户端停止。要解决这个问题,核心是让Redisson客户端的生命周期脱离单个Web上下文的管控。


方案1:使用Tomcat全局共享Redisson客户端(官方推荐)

通过Tomcat的全局命名资源管理Redisson客户端,让所有Web上下文共享同一个实例,单个上下文重载不会影响全局客户端的运行。

步骤:

  1. 在Tomcat全局配置中定义Redisson客户端资源
    编辑Tomcat的conf/server.xml,在<GlobalNamingResources>节点下添加如下配置:

    <GlobalNamingResources>
        <!-- 全局Redisson客户端资源 -->
        <Resource 
            name="redisson/RedissonClient"
            auth="Container"
            type="org.redisson.api.RedissonClient"
            factory="org.redisson.tomcat.RedissonClientFactory"
            configPath="/absolute/path/to/your/redisson.yaml"/>
    </GlobalNamingResources>
    

    注意configPath要填写Redisson配置文件的绝对路径。

  2. 在Web应用中引用全局资源
    编辑Web应用的META-INF/context.xml,添加资源链接:

    <Context>
        <!-- 引用全局Redisson客户端 -->
        <ResourceLink 
            name="redisson/RedissonClient"
            global="redisson/RedissonClient"
            type="org.redisson.api.RedissonClient"/>
        
        <!-- 配置RedissonSessionManager使用共享客户端 -->
        <Manager 
            className="org.redisson.tomcat.RedissonSessionManager"
            redissonClientJndiName="redisson/RedissonClient"/>
    </Context>
    

    这里不需要再指定configPath,因为客户端已经由全局资源初始化完成。

  3. 验证效果
    启动Tomcat后,Redisson客户端会由Tomcat全局管理,当Web上下文重载时,仅会销毁当前应用的SessionManager实例,不会触发全局客户端的关闭逻辑。


方案2:禁用Redisson关闭钩子并手动管理生命周期

通过配置禁用Redisson自带的关闭钩子,同时在Tomcat全局级别手动初始化和关闭客户端,脱离Web上下文的生命周期管控。

步骤:

  1. 修改Redisson配置文件
    在redisson.yaml中添加以下配置,关闭自动关闭钩子:

    # 禁用Redisson关闭钩子
    shutdownHook: false
    # 启用引用功能,避免客户端被意外回收
    referenceEnabled: true
    
  2. 编写全局监听器管理客户端生命周期
    创建一个Servlet上下文监听器,在Tomcat启动时初始化Redisson客户端,停止时手动关闭:

    import org.redisson.api.Redisson;
    import org.redisson.api.RedissonClient;
    import org.redisson.config.Config;
    import jakarta.servlet.ServletContextEvent;
    import jakarta.servlet.ServletContextListener;
    import jakarta.servlet.annotation.WebListener;
    
    @WebListener
    public class GlobalRedissonManager implements ServletContextListener {
        private static RedissonClient redissonClient;
    
        @Override
        public void contextInitialized(ServletContextEvent event) {
            // 加载Redisson配置并初始化客户端
            Config config = Config.fromYAML("/absolute/path/to/redisson.yaml");
            redissonClient = Redisson.create(config);
            // 将客户端实例存入全局上下文
            event.getServletContext().setAttribute("globalRedissonClient", redissonClient);
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent event) {
            // Tomcat停止时手动关闭客户端
            if (redissonClient != null && !redissonClient.isShutdown()) {
                redissonClient.shutdown();
            }
        }
    }
    
  3. 配置RedissonSessionManager使用全局客户端
    在context.xml的Manager标签中指定客户端实例:

    <Manager 
        className="org.redisson.tomcat.RedissonSessionManager"
        redissonClientAttributeName="globalRedissonClient"/>
    

方案3:关闭Tomcat上下文自动重载(备选)

如果不需要频繁重载Web上下文,可以将context.xml中的reloadable属性设为false:

<Context reloadable="false">
    <!-- 其他配置 -->
</Context>

这种方式简单直接,但会失去热重载应用的能力,仅适合不需要频繁更新的场景。


最佳实践

  1. 优先选择方案1,这是Redisson官方针对Tomcat上下文重载场景提供的标准解决方案,既能保证客户端稳定运行,又能避免连接池资源浪费。
  2. 避免每个Web应用单独初始化Redisson客户端,多个客户端实例会占用更多Redis连接资源,且容易出现生命周期管理问题。
  3. 若使用方案2,必须确保在Tomcat停止时手动关闭Redisson客户端,否则会导致Redis连接泄漏。

内容的提问来源于stack exchange,提问作者Muhammad Osama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:13:11