JBoss EJB 3.0と拡張機能

  メッセージ駆動型Bean
はじめに

JMS(Java Messaging Service)は、J2EEアプリケーションサーバの重要なサービスの一つです。JMSではメッセージ(たとえば、電子メールやインスタントメッセージ(IM)など)を通してサービスを非同期に起動できます。サーバは、トラフィックのピークを避けてメッセージの送信経路を変更したり、サービスレベル契約に応じたリクエスト処理を行ったりすることができます。つまり、高い拡張性と信頼性を持つエンタープライズシステムを構築するのに適しているのです。

JMSのクライアントは、サーバが管理するメッセージキュー(たとえば、電子メールの受信箱も一つのメッセージキューです)にメッセージを送信します。メッセージキューは特別なEJB、すなわちメッセージ駆動型Bean(MDB)が監視します。MDBは届いたメッセージを処理し、メッセージの内容に応じたサービスを実行します。MDBはJMSサービスの要求メッセージに対する終端の役目を果たします。

EJB 3.0でMDBを開発するのは非常に簡単です。アノテーションを使ってBeanに関連付けるメッセージキューを指定し、単純なインタフェースを実装するだけです

サンプルアプリケーション

このトレイルでは、投資計算プログラムをメッセージ駆動型Beanを使うように改変します。Webフォームの「計算」ボタンをクリックすると、JSPページ(calculator.jsp)は計算用の引数を持つメッセージをメッセージキューに送信します。そして次に別のJSPページ(check.jsp)に移り、定期的に計算結果が取得できるかどうかチェックします。

MDBはメッセージキューを監視し、届いたメッセージを取得し、内容を走査し、そして計算を行います。計算が終わると、結果をアプリケーション全体で共有しているキャッシュに保存します。結果は結果監視JSPページ(すなわち、check.jsp)がピックアップし、結果を表示します。

メッセージ駆動型Bean

EJB 3.0では、MDBのBeanクラスに@MessageDrivenアノテーションを使用して、どのメッセージキューを監視するか(すなわち、queue/mdbなど)を指定します。キューが存在しない場合はJBossコンテナがデプロイ時に自動的に作成します。XML設定ファイルは必要ありません!

BeanクラスはMessageListenerインタフェースを実装する必要があります。MessageListenerインタフェースはonMessage()メソッドを1つだけ定義しています。MDBが監視するキューにメッセージが届くと、JBossコンテナはBeanクラスのonMessage()メソッドを呼び、受信したメッセージを引数で渡します。この例では、CalculatorBean.onMessage()メソッドは、メッセージ本体を取得し、計算用引数を切り出し、計算を行い、JSPページが結果を受け取れるように、結果を静的なデータ管理クラスに保存します。サービス要求メッセージ内のタイムスタンプ"sent"を計算結果レコードの一意なIDとして使用しています(処理量の少ないwebサイトでは十分機能します)。JSPページcheck.jspはこのメッセージIDをもとに計算結果レコードをピックアップし、内容を表示します。


@MessageDriven(activationConfig =
{
  @ActivationConfigProperty(propertyName="destinationType",
    propertyValue="javax.jms.Queue"),
  @ActivationConfigProperty(propertyName="destination",
    propertyValue="queue/mdb")
})
public class CalculatorBean implements MessageListener {

  public void onMessage (Message msg) {
    try {
      TextMessage tmsg = (TextMessage) msg;
      Timestamp sent =
          new Timestamp(tmsg.getLongProperty("sent"));
      StringTokenizer st =
          new StringTokenizer(tmsg.getText(), ",");

      int start = Integer.parseInt(st.nextToken());
      int end = Integer.parseInt(st.nextToken());
      double growthrate = Double.parseDouble(st.nextToken());
      double saving = Double.parseDouble(st.nextToken());

      double result =
          calculate (start, end, growthrate, saving);
      RecordManager.addRecord (sent, result);

    } catch (Exception e) {
      e.printStackTrace ();
    }
  }

  // ... ...
}

Beanにメッセージを送信する

メッセージ駆動型Beanを使用するには、クライアント(この場合はJSPページcalculator.jsp)で標準JMS APIを使って、目的のMDBに対応するメッセージキューをキュー名(queue/mdb)で取得し、そのキューにメッセージを送信します。


try {
    InitialContext ctx = new InitialContext();
    queue = (Queue) ctx.lookup("queue/mdb");
    QueueConnectionFactory factory =
        (QueueConnectionFactory) ctx.lookup("ConnectionFactory");
    cnn = factory.createQueueConnection();
    sess = cnn.createQueueSession(false,
            QueueSession.AUTO_ACKNOWLEDGE);

} catch (Exception e) {
    e.printStackTrace ();
}
  
TextMessage msg = sess.createTextMessage(
    request.getParameter ("start") + "," +
    request.getParameter ("end") + "," +
    request.getParameter ("growthrate") + "," +
    request.getParameter ("saving")
);

sender = sess.createSender(queue);
sender.send(msg);
ソースコード参照

サーバ

  • CalculatorBean.java: queue/mdbキューを監視し、サービス要求メッセージを処理し、投資計算を行うメッセージ駆動型Bean
  • CalculationRecord.java: CalculatorBeanが行う各計算結果を保存するデータオブジェクトクラス。オブジェクトは、サービス要求メッセージのタイムスタンプ"sent"で一意に識別される。
  • RecordManager.java: システム全体でCalculationRecordオブジェクトを管理する静的クラス。最新の100レコードのみ保持し、レコードは要求メッセージのタイムスタンプ"sent"をもとに検索できる。

クライアント

  • calculator.jsp: ユーザからの入力を受け取り、投資計算のサービス要求メッセージを送信するクライアントJSP。
  • check.jsp: 静的クラスRecordManagerを使用してCalculatorBeanの処理が終了するのを待つクライアントJSP。待機するサービス要求メッセージは、メッセージのタイムスタンプ"sent"で識別される。
まとめ

このトレイルでは、EJB 3.0におけるメッセージ駆動型Beanの実装方法について学びました。@MessageDrivenアノテーションを使うことにより、複雑な設定ファイルは必要なくなります。しかし、メッセージ駆動型BeanそのものはPOJOではなく、MessageListenerインタフェースを実装する必要があります。JBoss ASでは、さらにエレガントなメッセージサービスを提供する別の方法を用意しています。では続けて次のトレイルに進んでみましょう。