このセクションでは、JMSのさまざまな高度なトピックについて説明します。 このガイドの他の箇所と比べると、このセクションの各トピックは関連性が薄いため、どこからでも読むことができます。 ここで説明されているトピックは通常、経験あるユーザが特別な状況でのみ使用するものであるため、JMSに精通していない場合はこのセクションを飛ばして、後からこれらの概念が必要になった場合に参照してください。
JMSでは、一時宛先と呼ばれる機能がサポートされています。これは、一時キューおよびトピックを動的に作成する場合に使用できます。 このような宛先は、管理者が作成するのではなく、通常、非持続メッセージの交換のための一時的なものです。 一時宛先にはそれぞれシステムにより生成される固有の名前があり、作成された接続範囲内でのみ使用できます。
JMSは一時宛先を使用して、Pub/SubまたはP2PメッセージングモデルでRPCのようなメカニズムを実装します。 この技術はリクエスタと呼ばれ、メッセージをパラメータとして受け取り、応答メッセージを返すrequestメソッドをサポートします。 リクエスタには、QueueRequestorとTopicRequestorがあります。 背後で、requestメソッドにより次の手順が実行されます。
次の図に、リクエスタの動作を示します。
ユーザがリクエスタを使用するのは、リモートサービスのRPCスタイルを呼び出す場合です。 コンシューマが宛先からメッセージを受信すると、このメッセージが処理され、一時宛先に返されます。 JMSで提供されているリクエスタは、非常に単純なので、アプリケーション開発者は、タイムアウトのサポートなどより洗練されたリクエスタを実装することもあります。
JMSには、接続内のコンシューマへのメッセージ配信を開始および停止する高度な機能が装備されています。 Connectionインタフェースは、次の2種類のメソッドをサポートしています。
start - 特定の接続により作成されたすべてのセッションに対するメッセージの配信を開始します。 startメソッドは、クライアントアプリケーションの初期化中にメッセージを受け取らないように、すべてのコンシューマおよびメッセージリスナを設定した後に呼び出すことができます。stop - メッセージ配信を停止します。 stopは、いつでも呼び出して、メッセージ配信を停止することができます。 stopメソッドは、すべての非同期メッセージリスナで個々のonMessageメソッドが完了されるまで返されません。 停止中、タイムアウト付きのreceiveへの呼び出しの期限が切れ、NULLが返されることがあります。 停止した接続は、再開してメッセージのフローに戻ることができます。
接続の停止および再開機能は、広範囲のアプリケーションで使用できる非常に便利な機能です。 たとえば、この機能をインタラクティブアプリケーション(GUIアプリケーションなど)で使用すると、ユーザは、組み込まれたJMS機能を使用してメッセージのフローを開始および停止できます。
すでに説明したとおり、セッションによりメッセージの送信と受信に対するシングルスレッドが提供されます。 つまり、receive、receiveNoWait、およびonMessageへのすべての呼び出しは、特定セッション内のすべてのコンシューマに対してシリアル化されます。 この機能は通常、スレッドセーフなコンシューマを安心して作成できるため、アプリケーション開発者には非常に便利です。
ただし、コンシューマアプリケーションによりJMSプロバイダに対する複数の接続が作成されない限り、基礎となるJVMおよびハードウェアの並行処理機能を利用して、クライアントアプリケーションが処理できるメッセージ数を最高にできないということにもなります。 接続はリソースをかなり消費するオブジェクトであるため、接続を多数作成することはお勧めできません。
コンシューマアプリケーションでの高度な並行処理機能が必要な場合に備え、JMS仕様では、接続コンシューマと呼ばれるオプションのJMS機能が定義されています。 接続コンシューマは、セッションレベルではなく接続レベルで「機能」します。そのため、セッションの並行処理制限に影響されません。
ConnectionConsumerは、メッセージを同時に処理できるオブジェクトです。 接続コンシューマは、TopicConnectionまたはQueueConnectionでcreateConnectionConsumerまたはcreateDurableConnectionConsumerメソッドを使用して作成されます。 接続コンシューマは、背後でServerSessionPoolに依存して、プールにより作成されたセッションオブジェクトのsetMessageListenerメソッドで設定された非同期コンシューマにメッセージを配信します。
次の図は、接続コンシューマ、サーバセッションプール、およびセッションの関係を示しています。 サーバセッションプールは、異なるスレッドで実行する複数のセッションを作成できるため、このアーキテクチャでは単一の接続を使用して、メッセージを同時に配信することができます。 セッションで分散トランザクション(XASession)がサポートされている場合、セッションのメッセージリスナは、オプションで、XAResourceを呼び出して、トランザクションによりメッセージを配信できます。
JMSプロバイダは、次の手順を実行して、接続コンシューマを使用したメッセージ配信を処理します。
startメソッドを呼び出します。runメソッドを呼び出す必要があります。 SessionはRunnableインタフェースを実装するため、任意のスレッドで実行できます。runメソッドは、そのメッセージをセッションメッセージリスナに配信します。 前に説明したとおり、リスナは、オプションで、セッションのXAResourceを呼び出して、トランザクションによりメッセージ配信を制御できます。要約すると、接続コンシューマアーキテクチャでは、ユーザは、メッセージを同時に配信できるだけでなく、実際に作業を実行するスレッドを制御することもできます。 このアーキテクチャは、メッセージ駆動型Beanを実装するアプリケーションサーバを主な対象としていますが、上級のアプリケーション開発者でも使用することができます。
分散トランザクションは、メッセージの送信または確認タスクを分散システムで実行している他のタスクと統合できるため、トランザクションセッションよりも優れています。 たとえば、メッセージの確認は、メッセージをデータベースに保存する場合と同じ作業単位で実行できます。
分散トランザクションは、ACIDのプロパティをサポートしています。
ACIDプロパティは、2段階コミット(2PC)プロトコルを使用して分散トランザクションを駆動することにより実行されます。 2PCプロトコルは、リソースコーディネータ(トランザクションマネージャ)と呼ばれるミドルウェアで制御されます。 リソースコーディネータは、次のアクションを実行することで2段階コミットを制御します。
メッセージを送信し、同じメッセージを受信するという操作を1つの分散トランザクションで行うことはできません。これは、このような動作が前に説明したACIDのプロパティ(孤立)に違反するからです。 宛先へのメッセージの入力、および宛先からのメッセージの削除は、2つの別々な操作なので、2つの異なるトランザクションで実行する必要があります。
前に説明したとおり、グローバルトランザクションでは、トランザクションに参加するリソースを追跡するコーディネータが必要です。 このコーディネータは、クラッシュが発生した場合にリソースの状態を記録するので、2段階コミットプロトコルが確実に完了(コミットまたはロールバック)されます。 コーディネータは、jBroker MQには搭載されていない別の製品です。
JMSが、コーディネータ(JTS/JTA)をサポートしているアプリケーションサーバのコンテキスト内で使用される場合、XAResourceオブジェクトの適切な処理は、コンテナにより自動的に行われます。 通常、アプリケーションプログラマは、JMSリソースの追加、削除、および駆動作業が自動的に行われるような制御された環境では、分散トランザクションの使用を選択します。