JavaでクライアントからのWebsocketメッセージを処理する方法は?

カレシュカラダラン

Websocketを使用してJavaでクライアントサーバーアプリケーションを開発しています。現在、すべてのクライアントメッセージは、以下に示すようにswitch-caseを使用して処理されます。

@OnMessage
public String onMessage(String unscrambledWord, Session session) {
    switch (unscrambledWord) {
    case "start":
        logger.info("Starting the game by sending first word");
        String scrambledWord = WordRepository.getInstance().getRandomWord().getScrambledWord();
        session.getUserProperties().put("scrambledWord", scrambledWord);
        return scrambledWord;
    case "quit":
        logger.info("Quitting the game");
        try {
            session.close(new CloseReason(CloseCodes.NORMAL_CLOSURE, "Game finished"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    String scrambledWord = (String) session.getUserProperties().get("scrambledWord");
    return checkLastWordAndSendANewWord(scrambledWord, unscrambledWord, session);
}

サーバーはクライアントからの50を超える異なる要求を処理する必要があり、その結果、50を超えるcaseステートメントが生成されます。そして将来的には、それが成長することを期待しています。クライアントからのWebsocketメッセージを処理するためのより良い方法はありますか?または、これは通常どのように行われるのですか?

関数ポインタにマッピングすることで長いswitch-caseシナリオを回避するための、ハッシュテーブルの使用についてどこかで読みました。これはJavaで可能ですか?または、より良い解決策はありますか?

ありがとう。

カレシュカラダラン

少しテストと調査を行った後、長いスイッチケースのシナリオを回避するための2つの選択肢を見つけました。

  1. 匿名クラスメソッド(ストラテジーパターン)
  2. 注釈付きの反射

匿名クラスの使用

匿名クラスメソッドが標準であり、次のコードはそれを実装する方法を示しています。この例ではRunnableを使用しました。さらに制御が必要な場合は、カスタムインターフェイスを作成します。

public class ClientMessageHandler {

    private final HashMap<String, Runnable> taskList = new HashMap<>();

    ClientMessageHandler() {

        this.populateTaskList();
    }

    private void populateTaskList() {

        // Populate the map with client request as key
       // and the task performing objects as value

        taskList.put("action1", new Runnable() {
            @Override
            public void run() {
                // define the action to perform.
            }
        });

       //Populate map with all the tasks
    }

    public void onMessageReceived(JSONObject clientRequest) throws JSONException {

        Runnable taskToExecute = taskList.get(clientRequest.getString("task"));

        if (taskToExecute == null)
            return;

        taskToExecute.run();
    }
}

このメソッドの主な欠点は、オブジェクトの作成です。たとえば、実行するタスクは100種類あります。この匿名クラスのアプローチでは、単一のクライアントに対して100個のオブジェクトが作成されます。5,000を超えるアクティブな同時接続が存在するアプリケーションでは、オブジェクトの作成が多すぎると手頃な価格ではありません。この記事をご覧くださいhttp://blogs.microsoft.co.il/gilf/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements/

注釈付きの反射

私はこのアプローチが本当に好きです。メソッドによって実行されるタスクを表すカスタムアノテーションを作成しました。タスクは単一のクラスによって実行されるため、Strategyパターンメソッドのようにオブジェクト作成のオーバーヘッドはありません。

注釈

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)

public @interface TaskAnnotation {
    public String value();
}

以下に示すコードは、クライアント要求キーをタスクを処理するメソッドにマップします。ここでは、マップがインスタンス化され、1回だけ入力されます。

public static final HashMap<String, Method> taskList = new HashMap<>();

public static void main(String[] args) throws Exception {

    // Retrieves declared methods from ClientMessageHandler class 

    Method[] classMethods = ClientMessageHandler.class.getDeclaredMethods();

    for (Method method : classMethods) {            
        // We will iterate through the declared methods and look for
        // the methods annotated with our TaskAnnotation

        TaskAnnotation annot = method.getAnnotation(TaskAnnotation.class);

        if (annot != null) {                
            // if a method with TaskAnnotation is found, its annotation
            // value is mapped to that method.

            taskList.put(annot.value(), method);
        }
    }

    // Start server
}

最後に、ClientMessageHandlerクラスは次のようになります。

public class ClientMessageHandler {

    public void onMessageReceived(JSONObject clientRequest) throws JSONException {

        // Retrieve the Method corresponding to the task from map
        Method method = taskList.get(clientRequest.getString("task"));

        if (method == null)
            return;

        try {
            // Invoke the Method for this object, if Method corresponding
            // to client request is found 

            method.invoke(this);
        } catch (IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            logger.error(e);
        }
    }

    @TaskAnnotation("task1")
    public void processTaskOne() {

    }

    @TaskAnnotation("task2")
    public void processTaskTwo() {

    }

    // Methods for different tasks, annotated with the corresponding
    // clientRequest code
}

このアプローチの主な欠点は、パフォーマンスの低下です。このアプローチは、直接メソッド呼び出しアプローチと比較して低速です。さらに、動的計画法を扱っていない限り、多くの記事がReflectionから離れることを提案しています。

これらの回答を読んで、リフレクションについて詳しく知るリフレクションとは何ですか。なぜそれが役立つのですか。

リフレクションパフォーマンス関連記事

Javaのリフレクションのより高速な代替手段

https://dzone.com/articles/the-performance-cost-of-reflection

最終結果

パフォーマンスへの影響を避けるために、アプリケーションでは引き続きswitchステートメントを使用しています。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

ビュークラスからダイアログへのメッセージ送信を処理する方法は?

分類Dev

alephを使用したWebSocketクライアントメッセージの処理

分類Dev

wait_for_message()関数でクライアントからのメッセージを無視する方法は?

分類Dev

WebSocketメッセージからのMethodArgumentNotValidExceptionを処理する

分類Dev

特定のポートからのメッセージを処理するアクターを指定する方法

分類Dev

Visual Studio Codeメッセージボックスでクリックイベントを処理する方法は?

分類Dev

テレグラムでボットアクションの後にユーザーメッセージを処理する方法は?

分類Dev

golangのWebSocketサーバーからクライアントにメッセージをアクティブに送信する方法

分類Dev

gRPC Javaサーバー:クライアントから受信した元のメッセージバイトを取得する方法はありますか?

分類Dev

WebSocketエンドポイントの外部からWebSocketメッセージを送信する方法は?

分類Dev

ベールボットで銀行メッセージからの応答を処理する方法は?

分類Dev

STOMPを使用してSpring WebSocketサーバーからWebSocketクライアントにメッセージを送信する方法

分類Dev

サーバーから websocket クライアントにメッセージを送信する

分類Dev

メッセージの処理中にAzureServiceBusクライアントを適切に破棄する

分類Dev

C ++のWebSocketクライアントとしてサーバーにメッセージを送信するにはどうすればよいですか?

分類Dev

XSocket.net。コントローラではないオブジェクトからクライアントにメッセージを送信する方法

分類Dev

PythonサーバーからJavaクライアントにメッセージを送信する方法

分類Dev

PerlでWebsocketの接続されたクライアントに定期的なメッセージを送信するにはどうすればよいですか?

分類Dev

バックグラウンドスクリプトのさまざまな機能で(コンテンツスクリプトからの)さまざまなメッセージを処理する方法は?

分類Dev

Faye Websocketを使用して特定のクライアントにメッセージを送信するにはどうすればよいですか?

分類Dev

ユーザーにプライベートメッセージを送信できないことを処理する最良の方法は何ですか?

分類Dev

アプリがバックグラウンドで実行されているときにFCMメッセージとタイトルを処理する方法

分類Dev

JavaからWebサービスを呼び出す「アクション付きのメッセージ」は受信者で処理できません」

分類Dev

PHP WebSocket –指定されたクライアントにメッセージを送信する方法は?

分類Dev

WebrtcクライアントはサーバーからのUDPメッセージを使用できますか?

分類Dev

ノードjsapiからzipファイルを返し、クライアント側で処理する方法は?

分類Dev

Pythonマルチスレッドサーバーは一度に1つのクライアントメッセージを処理できます

分類Dev

Javaのメインクラスからsrc.testパッケージにアクセスする方法、またはメインクラスからテストクラスを実行する方法

分類Dev

SSL:クライアントがサーバーからのメッセージを復号化する方法

Related 関連記事

  1. 1

    ビュークラスからダイアログへのメッセージ送信を処理する方法は?

  2. 2

    alephを使用したWebSocketクライアントメッセージの処理

  3. 3

    wait_for_message()関数でクライアントからのメッセージを無視する方法は?

  4. 4

    WebSocketメッセージからのMethodArgumentNotValidExceptionを処理する

  5. 5

    特定のポートからのメッセージを処理するアクターを指定する方法

  6. 6

    Visual Studio Codeメッセージボックスでクリックイベントを処理する方法は?

  7. 7

    テレグラムでボットアクションの後にユーザーメッセージを処理する方法は?

  8. 8

    golangのWebSocketサーバーからクライアントにメッセージをアクティブに送信する方法

  9. 9

    gRPC Javaサーバー:クライアントから受信した元のメッセージバイトを取得する方法はありますか?

  10. 10

    WebSocketエンドポイントの外部からWebSocketメッセージを送信する方法は?

  11. 11

    ベールボットで銀行メッセージからの応答を処理する方法は?

  12. 12

    STOMPを使用してSpring WebSocketサーバーからWebSocketクライアントにメッセージを送信する方法

  13. 13

    サーバーから websocket クライアントにメッセージを送信する

  14. 14

    メッセージの処理中にAzureServiceBusクライアントを適切に破棄する

  15. 15

    C ++のWebSocketクライアントとしてサーバーにメッセージを送信するにはどうすればよいですか?

  16. 16

    XSocket.net。コントローラではないオブジェクトからクライアントにメッセージを送信する方法

  17. 17

    PythonサーバーからJavaクライアントにメッセージを送信する方法

  18. 18

    PerlでWebsocketの接続されたクライアントに定期的なメッセージを送信するにはどうすればよいですか?

  19. 19

    バックグラウンドスクリプトのさまざまな機能で(コンテンツスクリプトからの)さまざまなメッセージを処理する方法は?

  20. 20

    Faye Websocketを使用して特定のクライアントにメッセージを送信するにはどうすればよいですか?

  21. 21

    ユーザーにプライベートメッセージを送信できないことを処理する最良の方法は何ですか?

  22. 22

    アプリがバックグラウンドで実行されているときにFCMメッセージとタイトルを処理する方法

  23. 23

    JavaからWebサービスを呼び出す「アクション付きのメッセージ」は受信者で処理できません」

  24. 24

    PHP WebSocket –指定されたクライアントにメッセージを送信する方法は?

  25. 25

    WebrtcクライアントはサーバーからのUDPメッセージを使用できますか?

  26. 26

    ノードjsapiからzipファイルを返し、クライアント側で処理する方法は?

  27. 27

    Pythonマルチスレッドサーバーは一度に1つのクライアントメッセージを処理できます

  28. 28

    Javaのメインクラスからsrc.testパッケージにアクセスする方法、またはメインクラスからテストクラスを実行する方法

  29. 29

    SSL:クライアントがサーバーからのメッセージを復号化する方法

ホットタグ

アーカイブ