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

如何在Spring EventListener中强制断开Stomp会话?

解决Spring Stomp WebSocket监听器中强制断开会话的问题

要实现强制断开会话,核心是主动维护WebSocketSession的引用——Spring默认不会直接暴露所有活跃会话的列表,得自己做会话管理。下面是具体实现步骤:

1. 自定义会话管理器,维护活跃会话

先写一个组件用来存储和管理所有活跃的WebSocketSession:

@Component
public class WebSocketSessionManager {
    // 用线程安全的Map存储会话,key为sessionId
    private final Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();

    // 添加会话
    public void addSession(WebSocketSession session) {
        sessionMap.put(session.getId(), session);
    }

    // 移除会话
    public void removeSession(WebSocketSession session) {
        sessionMap.remove(session.getId());
    }

    // 根据sessionId获取会话
    public WebSocketSession getSession(String sessionId) {
        return sessionMap.get(sessionId);
    }

    // 获取所有会话
    public Collection<WebSocketSession> getAllSessions() {
        return sessionMap.values();
    }
}

2. 注册拦截器,在握手时记录会话

通过WebSocketHandlerInterceptor在握手成功后将会话存入管理器,同时在会话关闭时移除(避免内存泄漏):

@Component
public class WebSocketSessionInterceptor implements WebSocketHandlerInterceptor {

    private final WebSocketSessionManager sessionManager;

    // 构造注入管理器
    public WebSocketSessionInterceptor(WebSocketSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) throws Exception {
        // 从请求中获取WebSocketSession
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            WebSocketSession session = (WebSocketSession) servletRequest.getServletRequest().getAttribute("javax.websocket.Session");
            if (session != null) {
                sessionManager.addSession(session);
            }
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        sessionManager.removeSession(session);
    }
}

然后在WebSocket配置类里注册这个拦截器:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    private final WebSocketSessionInterceptor sessionInterceptor;

    public WebSocketConfig(WebSocketSessionInterceptor sessionInterceptor) {
        this.sessionInterceptor = sessionInterceptor;
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.addDecoratorFactory(handler -> new WebSocketHandlerDecorator(handler) {
            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
                sessionInterceptor.afterConnectionClosed(session, closeStatus);
                super.afterConnectionClosed(session, closeStatus);
            }
        });
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS();
    }
}

3. 在EventListener中强制断开会话

现在可以在你的监听器里注入WebSocketSessionManager,获取目标会话后调用关闭方法:

@Component
public class WebSocketEventListener {

    private final WebSocketSessionManager sessionManager;

    public WebSocketEventListener(WebSocketSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    @EventListener
    public void handleWebSocketConnectListener(SessionConnectedEvent event) {
        // 从事件中提取sessionId
        SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.wrap(event.getMessage());
        String sessionId = headerAccessor.getSessionId();
        
        // 根据sessionId获取会话并断开
        WebSocketSession session = sessionManager.getSession(sessionId);
        if (session != null && session.isOpen()) {
            try {
                // 可根据业务场景选择CloseStatus,比如NORMAL、POLICY_VIOLATION等
                session.close(CloseStatus.NORMAL);
            } catch (IOException e) {
                // 按需处理异常
                e.printStackTrace();
            }
        }
    }
}

额外提示

  • 如果需要批量断开所有会话,直接遍历sessionManager.getAllSessions()调用close即可
  • 务必在会话关闭时从管理器中移除,防止内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:25:02