15

Websockets (Java EE 7) を使用して、接続されているすべてのクライアントに非同期でメッセージを送信するアプリケーションに取り組んでいます。サーバー (Websocket エンドポイント) は、新しい記事 (私のアプリのエンゲージメント モーダル) が作成されるたびに、これらのメッセージを送信する必要があります。

Websocket エンドポイントへの接続が確立されるたびに、対応するセッションをリストに追加して、外部からアクセスできるようにします。

しかし、私が抱えていた問題は、すべてのクライアントが外部 (他のビジネス クラス) から接続するこの作成された websocket エンドポイントにアクセスすると、既存のインスタンス (シングルトンなど) を取得してしまうことです。

それで、クライアントからのリクエストがいつでもwebsocket内部メカニズムによって作成されるため、新しいMyWebsocketEndPoint()として作成できないため、websocketエンドポイントの既存のインスタンスを取得する方法を教えてください。受け取った。

参照の場合:

private static WebSocketEndPoint INSTANCE = null;

public static WebSocketEndPoint getInstance() {
if(INSTANCE == null) {
// Instead of creating a new instance, I need an existing one
    INSTANCE = new WebSocketEndPoint ();
}
        return INSTANCE;
}

前もって感謝します。

4

2 に答える 2

23

コンテナーは、クライアント接続ごとにエンドポイントの個別のインスタンスを作成するため、実行しようとしていることができません。しかし、あなたがしようとしているのは、イベントが発生したときにすべてのアクティブなクライアント接続にメッセージを送信することだと思います。これはかなり簡単です。

このjavax.websocket.Sessionクラスには、そのセッションに関連付けられたエンドポイントを表すインスタンスgetBasicRemoteを取得するメソッドがあります。RemoteEndpoint.Basic

を呼び出して開いているすべてのセッションを取得し、Session.getOpenSessions()それらを反復処理できます。ループは、各クライアント接続にメッセージを送信します。簡単な例を次に示します。

@ServerEndpoint("/myendpoint")
public class MyEndpoint {
  @OnMessage
  public void onMessage(Session session, String message) {
    try {  
      for (Session s : session.getOpenSessions()) {
        if (s.isOpen()) {
          s.getBasicRemote().sendText(message);
        }
    } catch (IOException ex) { ... }
  } 
} 

しかし、あなたのケースでは、おそらく CDI イベントを使用して、すべてのクライアントへの更新をトリガーしたいと思うでしょう。その場合、Websocket エンドポイント クラスのメソッドが監視する CDI イベントを作成します。

@ServerEndpoint("/myendpoint")
public class MyEndpoint {
  // EJB that fires an event when a new article appears
  @EJB
  ArticleBean articleBean;
  // a collection containing all the sessions
  private static final Set<Session> sessions = 
          Collections.synchronizedSet(new HashSet<Session>());

  @OnOpen
  public void onOpen(final Session session) {
    // add the new session to the set
    sessions.add(session);
    ...
  }

  @OnClose
  public void onClose(final Session session) {
    // remove the session from the set
    sessions.remove(session);
  }

  public void broadcastArticle(@Observes @NewArticleEvent ArticleEvent articleEvent) {
    synchronized(sessions) {
      for (Session s : sessions) {
        if (s.isOpen()) {
          try {
            // send the article summary to all the connected clients
            s.getBasicRemote().sendText("New article up:" + articleEvent.getArticle().getSummary());
          } catch (IOException ex) { ... }
        }
      }
    }
  }
}

上記の例の EJB は次のようになります。

...
@Inject
Event<ArticleEvent> newArticleEvent;

public void publishArticle(Article article) {
  ...
  newArticleEvent.fire(new ArticleEvent(article));
  ...
}

WebSocketsおよびCDI Eventsに関する Java EE 7 チュートリアルの章を参照してください。

編集:@Observerイベントをパラメーターとして使用するようにメソッドを変更しました。

編集 2: @gcvt ごとに、broadcastArticle のループを同期でラップしました。

編集 3: Java EE 7 チュートリアルへのリンクを更新しました。よくやった、オラクル。おいおい。

于 2013-08-29T00:19:46.523 に答える