1. 序章

簡単に言うと、Enterprise JavaBean(EJB)は、アプリケーションサーバー上で実行されるJEEコンポーネントです。

このチュートリアルでは、非同期コンテキストでのメッセージ処理の処理を担当するメッセージ駆動型Bean(MDB)について説明します。

MDBは、EJB2.0仕様以降のJEEの一部です。 EJB 3.0では、注釈の使用が導入され、これらのオブジェクトの作成が容易になりました。 ここでは、注釈に焦点を当てます。

2. いくつかの背景

メッセージ駆動型Beanの詳細に入る前に、メッセージングに関連するいくつかの概念を確認しましょう。

2.1. メッセージング

メッセージングは通信メカニズムです。 メッセージングを使用することにより、プログラムは、異なるプログラム言語で記述されている場合や、異なる運用システムに存在する場合でも、データを交換できます。

緩く結合されたソリューションを提供します。 情報の作成者も消費者もお互いの詳細を知る必要はありません

したがって、それらを同時にメッセージングシステムに接続する必要はありません(非同期通信)。

2.2. 同期および非同期通信

同期通信中、リクエスターは応答が返されるまで待機します。 その間、リクエスタープロセスはブロックされたままになります。

一方、非同期通信では、リクエスターは操作を開始しますが、それによってブロックされることはありません。 リクエスターは他のタスクに進み、後で応答を受け取ることができます。

2.3. JMS

Javaメッセージサービス(「JMS」)は、メッセージングをサポートするJavaAPIです。

JMSは、ピアツーピアおよびパブリッシュ/サブスクライブメッセージングモデルを提供します。

3. メッセージ駆動型Bean

MDBは、メッセージがメッセージングシステムに到着するたびにコンテナによって呼び出されるコンポーネントです。その結果、このイベントはこのBean内のコードをトリガーします。

受信したデータをブラウザに表示したり、解析してデータベースに保存したりするため、MDB onMessage()メソッド内で多くのタスクを実行できます。

別の例は、何らかの処理の後にデータを別のキューに送信することです。 それはすべて私たちのビジネスルールに帰着します。

3.1. メッセージ駆動型Beanのライフサイクル

MDBには2つの状態しかありません。

  1. コンテナには存在しません
  2. 作成され、メッセージを受信する準備ができました

依存関係が存在する場合は、MDBが作成された直後に挿入されます。

メッセージを受信する前に命令を実行するには、メソッドに@javax.ejb。PostConstructでアノテーションを付ける必要があります。

依存性注入と@javax.ejb。PostConstructの実行はどちらも1回だけ行われます。

その後、MDBはメッセージを受信する準備が整います。

3.2. 取引

メッセージは、トランザクションコンテキスト内でMDBに配信できます。

onMessage()メソッド内のすべての操作が単一のトランザクションの一部であることを意味します。

したがって、ロールバックが発生した場合、メッセージシステムはデータを再配信します。

4. メッセージ駆動型Beanの操作

4.1. 消費者の作成

メッセージ駆動型Beanを作成するには、クラス名宣言の前に @javax.ejb.MessageDrivenアノテーションを使用します。

着信メッセージを処理するには、 MessageListenerインターフェイスのonMessage()メソッドを実装する必要があります。

@MessageDriven(activationConfig = { 
    @ActivationConfigProperty(
      propertyName = "destination", 
      propertyValue = "tutorialQueue"), 
    @ActivationConfigProperty(
      propertyName = "destinationType", 
      propertyValue = "javax.jms.Queue")
})
public class ReadMessageMDB implements MessageListener {

    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage) message;
        try {
            System.out.println("Message received: " + textMessage.getText());
        } catch (JMSException e) {
            System.out.println(
              "Error while trying to consume messages: " + e.getMessage());
        }
    }
}

この記事では.xml記述子ではなく注釈に焦点を当てているため、使用します @ActivationConfigProperty それよりも

@ActivationConfigProperty は、その構成を表すキー値プロパティです。 ActivationConfig 内で2つのプロパティを使用して、キューとMDBが消費するオブジェクトのタイプを設定します。

onMessage()メソッド内で、メッセージパラメータを TextMessage、BytesMessage、MapMessageStreamMessageまたはObjectMessageにキャストできます。

ただし、この記事では、標準出力のメッセージコンテンツのみを確認します。

4.2. プロデューサーの作成

セクション2.1で説明したように、プロデューサーサービスとコンシューマーサービスは完全に独立しており、異なるプログラミング言語で作成することもできます。

Javaサーブレットを使用してメッセージを生成します。

@Override
protected void doGet(
  HttpServletRequest req, 
  HttpServletResponse res) 
  throws ServletException, IOException {
 
    String text = req.getParameter("text") != null ? req.getParameter("text") : "Hello World";

    try (
        Context ic = new InitialContext();
 
        ConnectionFactory cf = (ConnectionFactory) ic.lookup("/ConnectionFactory");
        Queue queue = (Queue) ic.lookup("queue/tutorialQueue");
 
        Connection connection = cf.createConnection();
    ) {
        Session session = connection.createSession(
          false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer publisher = session
          .createProducer(queue);
 
        connection.start();

        TextMessage message = session.createTextMessage(text);
        publisher.send(message);
 
    } catch (NamingException | JMSException e) {
        res.getWriter()
          .println("Error while trying to send <" + text + "> message: " + e.getMessage());
    } 

    res.getWriter()
      .println("Message sent: " + text);
}

ConnectionFactoryおよびQueueインスタンスを取得した後、ConnectionおよびSessionを作成する必要があります。

セッションを作成するには、createSessionメソッドを呼び出します。

createSession の最初のパラメーターは、セッションがトランザクションの一部であるかどうかを定義するbooleanです。

2番目のパラメーターは、最初のパラメーターがfalseの場合にのみ使用されます。 これにより、着信メッセージに適用され、 Session.AUTO_ACKNOWLEDGE、Session.CLIENT_ACKNOWLEDGE 、およびSession.DUPS_OK_ACKNOWLEDGEの値を取得する確認応答方法を説明できます。

これで、接続を開始し、セッションオブジェクトにテキストメッセージを作成して、メッセージを送信できます。

同じキューにバインドされているコンシューマーは、メッセージを受信して非同期タスクを実行します。

また、 JNDI オブジェクトの検索とは別に、try-with-resourcesブロックのすべてのアクションは、 JMSException に接続しようとするなどのエラーが発生した場合に、接続が閉じていることを確認します。キューが存在しないか、接続するポート番号が間違っています。

5. メッセージ駆動型Beanのテスト

次のように、SendMessageServletGETメソッドを介してメッセージを送信します。

http://127.0.0.1:8080/producer/SendMessageServlet?text=送信するテキスト

また、 http://127.0.0.1:8080/producer/SendMessageServlet.のように、パラメータを送信しない場合、サーブレットは「HelloWorld」をキューに送信します。

6. 結論

メッセージ駆動型Beanを使用すると、キューベースのアプリケーションを簡単に作成できます。

したがって、 MDBを使用すると、アプリケーションをローカライズされた責任を持つより小さなサービスに分離でき、システム障害から回復できるはるかにモジュール化されたインクリメンタルシステムが可能になります。

いつものように、コードはGitHubオーバーです。