From 0cded6758a031ff6353b7c9fae13d5b023ece579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=9E=E5=AE=9D=E5=B1=B1?= <1253070437@qq.com> Date: Sat, 7 Feb 2026 21:53:47 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=81=9C=E6=AD=A2=E9=A1=B9=E7=9B=AE=E6=97=B6ws?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E3=80=81=E5=90=AF=E5=8A=A8=E6=97=B6=E5=9B=A0?= =?UTF-8?q?=E4=B8=BA=E6=97=A5=E5=BF=97=E9=85=8D=E7=BD=AE=E8=BF=87=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E5=86=99=E6=B3=95=E6=8A=A5=E7=BA=A2=E8=89=B2=E8=AD=A6?= =?UTF-8?q?=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websocket/DevMessageWebSocket.java | 47 +++++++++++++++++++ .../src/main/resources/logback-spring.xml | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/snowy-plugin/snowy-plugin-dev/src/main/java/vip/xiaonuo/dev/modular/message/websocket/DevMessageWebSocket.java b/snowy-plugin/snowy-plugin-dev/src/main/java/vip/xiaonuo/dev/modular/message/websocket/DevMessageWebSocket.java index 2e837fb4..ad58d5d3 100644 --- a/snowy-plugin/snowy-plugin-dev/src/main/java/vip/xiaonuo/dev/modular/message/websocket/DevMessageWebSocket.java +++ b/snowy-plugin/snowy-plugin-dev/src/main/java/vip/xiaonuo/dev/modular/message/websocket/DevMessageWebSocket.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.http.HttpUtil; import cn.hutool.extra.spring.SpringUtil; import cn.hutool.json.JSONUtil; +import jakarta.annotation.PreDestroy; import jakarta.websocket.*; import jakarta.websocket.server.ServerEndpoint; import lombok.extern.slf4j.Slf4j; @@ -12,12 +13,14 @@ import org.springframework.stereotype.Component; import vip.xiaonuo.dev.modular.message.service.DevMessageService; import java.io.IOException; +import java.nio.channels.ClosedChannelException; import java.nio.charset.Charset; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; /** * 站内信WebSocket @@ -40,6 +43,31 @@ public class DevMessageWebSocket { */ private static final ConcurrentHashMap SESSION_USER_MAP = new ConcurrentHashMap<>(); + /** + * 应用关闭标志 + */ + private static final AtomicBoolean IS_SHUTTING_DOWN = new AtomicBoolean(false); + + /** + * 应用关闭时优雅关闭所有WebSocket连接 + */ + @PreDestroy + public void destroy() { + IS_SHUTTING_DOWN.set(true); + log.info("应用关闭,开始清理WebSocket连接,当前连接数: {}", SESSION_POOL.size()); + SESSION_POOL.values().forEach(session -> { + try { + if (session.isOpen()) { + session.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, "服务器关闭")); + } + } catch (Exception e) { + // 忽略关闭时的异常 + } + }); + SESSION_POOL.clear(); + SESSION_USER_MAP.clear(); + } + @OnOpen public void onOpen(Session session) { try { @@ -82,10 +110,29 @@ public class DevMessageWebSocket { @OnError public void onError(Session session, Throwable error) { + // 应用关闭时或通道已关闭时,忽略相关异常 + if (IS_SHUTTING_DOWN.get() || isClosedException(error)) { + onClose(session); + return; + } log.error("WebSocket onError", error); onClose(session); } + /** + * 判断是否为关闭相关的异常 + */ + private boolean isClosedException(Throwable error) { + if (error instanceof ClosedChannelException) { + return true; + } + if (error instanceof IOException) { + Throwable cause = error.getCause(); + return cause instanceof ClosedChannelException; + } + return false; + } + @OnMessage public void onMessage(String message, Session session) { // 收到消息,暂不处理 diff --git a/snowy-web-app/src/main/resources/logback-spring.xml b/snowy-web-app/src/main/resources/logback-spring.xml index d7109578..90c2e72b 100644 --- a/snowy-web-app/src/main/resources/logback-spring.xml +++ b/snowy-web-app/src/main/resources/logback-spring.xml @@ -5,7 +5,7 @@ - +