ct 3 месяцев назад
Родитель
Сommit
e129c8b4b2

+ 49 - 0
fs-service/src/main/java/com/fs/core/config/RedissonShutdownListener.java

@@ -0,0 +1,49 @@
+package com.fs.core.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RedissonClient;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+/**
+ * Web 应用销毁时主动关闭 Redisson,避免 Tomcat 报错:
+ * "The web application [ROOT] appears to have started a thread named [redisson-netty-*] but has failed to stop it."
+ */
+@Slf4j
+public class RedissonShutdownListener implements ServletContextListener {
+
+    /** 关闭后等待 Netty 线程退出的时间(毫秒) */
+    private static final int SHUTDOWN_WAIT_MS = 3000;
+
+    @Override
+    public void contextDestroyed(ServletContextEvent sce) {
+        try {
+            WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
+            if (ctx == null) {
+                return;
+            }
+            if (!ctx.containsBean("redissonClient")) {
+                return;
+            }
+            RedissonClient client = ctx.getBean(RedissonClient.class);
+            if (client != null && !client.isShutdown()) {
+                log.info("[Redisson] 应用卸载,正在关闭 RedissonClient 以避免 Netty 线程泄漏");
+                client.shutdown();
+                Thread.sleep(SHUTDOWN_WAIT_MS);
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            log.warn("[Redisson] 等待关闭时被中断", e);
+        } catch (Exception e) {
+            log.warn("[Redisson] 关闭 RedissonClient 时异常", e);
+        }
+    }
+
+    @Override
+    public void contextInitialized(ServletContextEvent sce) {
+        // no-op
+    }
+}