【问题标题】:Server-initiated WebSocket broadcast in JSR-356JSR-356 中服务器发起的 WebSocket 广播
【发布时间】:2014-08-14 06:27:38
【问题描述】:

在 JSR-356 中广播服务器发起的 WebSocket 消息的最佳实践是什么?

为了澄清,我知道使用@OnMessage 注释时回复甚至广播是如何工作的,但我想从服务器发送事件而不先从客户端接收消息。换句话说,我想我需要在下面的代码中引用MessageServerEndpoint 实例。

我见过下面的解决方案,但是它使用的是静态方法,不是很优雅。

@ServerEndpoint(value = "/echo")
public class MessageServerEndpoint {
    private static Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());

    @OnOpen
    public void onOpen(Session session) {
        sessions.add(session);
    }

    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        sessions.remove(session);
    }

    // Static method - I don't like this at all
    public static void broadcast(String message) {
        for (Session session : sessions) {
            if (session.isOpen()) {
                session.getBasicRemote().sendText(message);
            }
        }
    }
}

public class OtherClass {
    void sendEvent() {
        MessageServerEndpoint.broadcast("test");
        // How do I get a reference to the MessageServerEndpoint instance here instead?
    }
}

【问题讨论】:

  • 很容易去除静电。什么不优雅?
  • 抱歉,我认为我的问题不是很清楚。我不确定如何从程序的其余部分访问 MessageServerEndpoint 实例。
  • 如何使用@ServerEndpoint` 注释创建一个servlet。 servlet 将处理正常的 websocket 请求,并执行您的自定义服务器驱动请求。

标签: java websocket jsr356


【解决方案1】:

我通过扩展ServerEndpointConfig.Configurator 并覆盖getEndpointInstance() 解决了这个问题,我可以在其中保存端点实例:

public class MyEndpointConfigurator extends ServerEndpointConfig.Configurator
    private Set<MyEndpoint> endpoints = Collections.synchronizedSet(new HashSet<>());

    @Override
    public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
        try {
            T endpoint = endpointClass.newInstance();
            MyEndpoint myEndpoint = (MyEndpoint) endpoint;
            myEndpoint.setConfigurator(this);
            endpoints.add(myEndpoint);
            return endpoint;
        } catch (IllegalAccessException e) {
            throw new InstantiationException(e.getMessage());
        }
    }

    // Call this from MyEndpoint.onClose()
    public void removeInstance(MyEndpoint endpoint) {
        endpoints.remove(endpoint);
    }
}

因为我有对MyEndpointConfigurator 的引用,所以我也有对所有端点的引用。

它仍然感觉像一个 hack,但似乎可以解决问题。

【讨论】:

  • 我在 Tomcat 上使用了 org.apache.tomcat.websocket.server.DefaultServerEndpointConfigurator,效果非常好。您的帖子为我指明了正确的方向
猜你喜欢
  • 2013-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-04
  • 2017-07-20
  • 2015-08-08
  • 2016-04-23
  • 1970-01-01
相关资源
最近更新 更多