java - Websocket服务器: Handle close event per session

标签 java jakarta-ee websocket

有没有办法处理每个 session 的 websocket 的服务器端关闭事件?这就是我目前的实现方式:

@ServerEndpoint("/ws")
public class WebsocketServerEndpoint {
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Websocket opened");
        CustomWebsocketHandler handler = new CustomWebsocketHandler(session); // see below
        // ...
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        System.out.println("Websocket closed. Reason: " + reason);
    }
}

但我想将新的 Session 实例包装在自定义对象内。对于消息,我可以通过 addMessageHandler 将处理程序直接添加到特定 session 。但是如何为该特定 session 上的 onClose 事件添加处理程序?:

class CustomWebsocketHandler {
    public CustomWebsocketHandler(Session session) {
        session.addMessageHandler((MessageHandler.Whole<String>) this::handleMessage);
        // How to hook up close event to handleClose()?
    }

    private void handleMessage(String message) { /* ... */ }

    private void handleClose() { /* ... */ }
}

我的一个想法是跟踪 WebsocketServerEndpoint 中的每个 session 及其各自的 CustomWebsocketHandler 实例,并针对每个关闭事件遍历它们,转发该事件。然而,这非常麻烦并且容易出错:

@ServerEndpoint("/ws")
public class WebsocketServerEndpoint {
    private List<Pair<Session, CustomWebsocketHandler>> sessions = new ArrayList<>();

    @OnOpen
    public void onOpen(Session session) {
        // ...
        sessions.add(Pair.of(session, handler)); // not hashable I suppose
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        // ...
        for (Iterator<Pair<Session, CustomWebsocketHandler>> it = sessions.iterator(); it.hasNext(); ) {
            Pair<Session, CustomWebsocketHandler> pair = it.next();
            if (pair.getLeft() == session) {
                pair.getRight().handleClose();
                it.remove();
                break;
            }
        }
    }
}

在客户端,这很容易,因为每个连接都可以使用自己的 ClientEndpoint 注释类实例:

webSocketContainer.connectToServer(endpointInstance, websocketURI);

服务器端是否存在类似的情况,或者是否可以完全处理每个 session 的服务器端 onClose (最终还有 onError)事件?

最佳答案

默认情况下,会为每个新客户端创建 ServerEndpoint 注释类的新实例。此行为由 ServerEndpointConfig.Configurator#getEndpointInstance 控制方法:

The platform default implementation of this method returns a new endpoint instance per call, thereby ensuring that there is one endpoint instance per client, the default deployment cardinality.

这意味着可以安全地将特定于 session 的状态存储在 WebsocketServerEndpoint 类本身中,而无需手动将 session 与自定义连接实例关联起来:

@ServerEndpoint("/ws")
public class WebsocketServerEndpoint {
    private CustomWebsocketHandler handler;

    @OnOpen
    public void onOpen(Session session) {
        handler = new CustomWebsocketHandler(session);
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        handler.handleClose();
    }
}

此时,将带注释的类 WebsocketServerEndpoint 本身作为所需的 CustomWebsocketHandler 可能会更容易,因为它具有相同的语义:每个连接一个实例并处理 websocket 事件。

关于java - Websocket服务器: Handle close event per session,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46341161/

相关文章:

mysql - 使用 Angular、Node 和 mysql 实现 WebSockets

java - 如何在 android 中从 Arraylist 日期按降序对日期进行排序?

javax.annotation.security 不是基于角色的访问控制?

java - 从 JSF 访问复合键时目标无法访问

java - 从两个表创建一个引用表

jsf - 记录器,从@Inject 转换为生产者

java - 中间代码生成

java - Jsf 用旧值更新模型值

java - 有人对 ping 和 pong 框架有什么想法吗?

ruby-on-rails - 使用 Websockets 部署瘦