このセクションでは、JMSの詳細について説明します。特に、JMSプロバイダの信頼性を理解する上で基本となる、確認モードについて説明します。また、このセクションでは、メッセージプロデューサとコンシューマ、および例外リスナとメッセージセレクタについても説明します。
前に説明したとおり、発行/購読モデルとP2Pモデルは多くの点で共通するため、特に注意書きがない限り、このセクションにおける情報は両方のモデルに適用されます。JMS APIの用語に関するこれら2つのモデルの大きな違いは、P2Pモデルではキューブラウザを使用し、発行/購読モデルでは永続的サブスクライバを使用するという点のみです。
メッセージ確認は、コンシューマ側の概念で、コンシューマがメッセージを受信したことをJMSプロバイダにどのように知らせるかに関係します。プロデューサの確認通知は、トピックパブリッシャのpublish
メソッド、またはキュー送信者のsend
メソッドのいずれかの正常な呼び出しによるものだけです。
メッセージの確認は、JMSプロバイダが同じメッセージを同じコンシューマに複数回送信しないためです。また、JMSプロバイダが、メッセージに使用しているリソースを開放できるということも意味します。リソースの消費を最小限にするために、コンシューマアプリケーションはできるだけ早くメッセージを確認する必要があります。
JMSでは、いくつかのメッセージ確認モードがサポートされています。
コンシューマアプリケーションはSessionインタフェースで定義されたDUPS_OK_ACKNOWLEDGE
定数を使用してこの確認モードを指定します。.このモードを使用すると、セッションは、厳しい制限なしにメッセージを確認します。そのため、メッセージ処理は速くなりますが、JMSに障害が発生した場合、複製メッセージが複数回配信されることがあります。この確認モードは、メッセージの複製をサポートしているアプリケーションでのみ使用してください。
これはSessionインタフェースで定義されたAUTO_ACKNOWLEDGE定数を使用するよう指定されたデフォルト確認モードです。各メッセージに対して、セッションは、次のいずれかの場合に、クライアントがメッセージを受信したことを自動的に確認します。
receive
またはreceiveNoWait
への呼び出しによりメッセージが返される直前
コンシューマがMessageListenerを呼び出した後、onMessageメソッドが返される直後
メッセージ処理中にJMSプロバイダまたはメッセージコンシューマに障害が発生した場合、自動確認モードでは、そのメッセージは再送信されるか失われます。
同期受信では、JMSによりメッセージが確認されたものの受信によりメッセージがコンシューマに返される前にJMSがクラッシュすると、メッセージは失われます。非同期のメッセージリスナでは、onMessage
の完了後で確認が記録される前にJMSがクラッシュすると、メッセージが複製されます。
これらの状況は、JMS実装の制限ではなく、分散システムで自動確認を使用する場合の性質です。このような状況を回避できるのは、クライアントで持続的な状態を維持するか、分散トランザクションを使用する場合のみです。
コンシューマアプリケーションはSessionインタフェースで定義されたCLIENT_ACKNOWLEDGE
定数を使用して確認モードを指定します。.この確認モードでは、コンシューマはメッセージの確認時期をより細かく制御できます。 コンシューマは複数のメッセージをグループ化し、Messageのacknowledge
メソッドを呼び出してJMSプロバイダにメッセージ(およびこの時点までに受信されたほかのメッセージすべて)が消費されていることを知らせます。
コンシューマがクライアント確認を使用する場合、セッションのrecover
メソッドを使用して、そのセッションの最後のチェックポイントに戻ることができます。このようにすると、セッションにより、コンシューマで確認されていないすべてのメッセージが再送信されます。また、クライアントで障害が発生し、そのクライアントが後でそのキューやトピックに再接続すると、セッションが回復され、コンシューマは確認されていないすべてのメッセージを受け取ることになるので注意してください。
セッションでは、トランザクションセッションと呼ばれる別の確認モードがサポートされています。トランザクションセッションとは、1つの作業単位として処理される、消費および生成メッセージの関連グループのことです。トランザクションは、コミットまたはロールバックのいずれかを実行できます。
セッションのcommit
メソッドが呼び出されると、消費メッセージが確認され、関連する生成メッセージが送信されます。セッションのrollback
メソッドが呼び出されると、生成メッセージが破棄され、消費メッセージが回復されます。
トランザクションセッションには、常に、「現在の」トランザクションがあり、アプリケーションは明示的にはトランザクションを開始しません。commit
またはrollback
メソッドが呼び出された直後に、現在のトランザクションが終了し、すぐに新しいトランザクションが開始されます。これらのメソッドは、トランザクションセッションでのみ呼び出すことができます。
次の図は、メッセージおよび確認を保持するための「箱」を使用して、トランザクションセッションを説明したものです。MSGおよびACKは、commit
またはrollback
メソッドが呼び出されたるときにフラッシュされます。
トランザクションセッションは、通常、メッセージを自動的に消費または生成するときに使用されます。アプリケーションにより、宛先間でメッセージを送信する場合、トランザクションセッションを使用して、メッセージが正常に転送される、または全く転送されないようにする必要があります。この場合、commit
メソッドを各メッセージの後に呼び出します。
メッセージプロデューサは、メッセージを宛先に送信または発行します。 QueueSenderインタフェースおよびTopicPublisherインタフェースでは、メッセージを送信するためのsend
メソッドまたはpublish
メソッドいずれかについて、いくつかの種類がサポートされています。
プロデューサアプリケーションは、メッセージを作成し、メッセージのさまざまなプロパティを設定する必要があります。これらのプロパティがsend
またはpublish
メソッドで指定されない場合、JMSにより、キュー送信者またはトピックパブリッシャのデフォルト値として使用される値が割り当てられます。
send
またはpublish
メソッドが正常に呼び出されると、JMSはメッセージを受信します。持続メッセージの場合、メッセージがいくつかの永続的な保存場所に正常に書き込まれ、受信者が確認するまでメッセージが失われないことが保証されます。
メッセージコンシューマは、宛先からメッセージを受信します。 QueueReceiverインタフェースおよびTopicSubscriberインタフェースはいずれも、双方向の受信メッセージをサポートするMessageConsumerを拡張します。
クライアントは、MessageConsumerインタフェースで定義されている受信メソッドのいずれかを呼び出します。
receive
- タイムアウトなしで呼び出すことができます。コンシューマは、メッセージの取り出しを無制限に、または指定時間だけ保護します。タイムアウトになる前にメッセージが宛先で使用できない場合、NULLが返されます。receiveNoWait
- メッセージに対して呼び出すことができ、すぐにNULLが返されるか、コンシューマの登録先の宛先でメッセージが使用できる場合、そのメッセージが返されます。
コンシューマアプリケーションは、メッセージ受信を開始する前に、Connectionオブジェクトでstart
メソッドを呼び出す必要があります。start
メソッドは、JMSプロバイダへの信号で、接続により作成されるすべてのセッションに対してメッセージのフローを開始します。
クライアントはsetMessageListener
メソッドを使用するMessageConsumerでMessageListenerを登録します。非同期および同期モデルを併用することはできず、メッセージリスナでコンシューマの受信メソッドを呼び出すこともできません。
メッセージリスナは、onMessage
メソッドを実装するオブジェクトです。このメソッドには、JMSメッセージである1つの引数があります。メッセージリスナは、例外を発生させることができないため、コンシューマアプリケーションは常に例外を探し、これらを処理する必要があります。
本来、JMSプロバイダは接続に関する問題を解決します。エラーが発生したときに、アプリケーションがメッセージを送受信しようとすると、プロバイダは例外を生成します。ただし、メッセージリスナを使用している場合、コンシューマは、プロバイダがメッセージリスナを呼び出すまで待機するため、プロバイダによる例外生成は不可能です。
そのためJMSは、クライアントとの例外の通信に使用されるExceptionListenerというインタフェースをサポートしています。例外リスナは、主に、非同期通信のサポートに使用できますが、クライアントアプリケーションで使用することをお勧めします。
例外リスナは、ConnectionオブジェクトでsetExceptionListener
メソッドを使用して設定されます。通常のメッセージリスナとは対称的に、例外リスナは、各コンシューマではなく各接続に対して一度設定されます。デフォルトでは、接続に例外リスナはありません。
これまで、P2Pモデルおよび発行/購読メッセージモデルについて説明してきました。 P2Pおよび発行/購読はいずれも特殊なメッセージ受信者をサポートします。P2Pモデルはキューブラウザ、発行/購読モデルは永続的サブスクライバをサポートしています。
キューブラウザとは、メッセージを受信できるが、消費することはできない特別なコンシューマのことです。 キューブラウザは、キューから実際に削除せずにキューメッセージを参照できるメソッドを持つ、QueueBrowserインタフェースをサポートしています。
QueueBrowserインタフェースは、要素がメッセージである有名なEnumerationを提供します。この一覧のメッセージの順序は、通常のキュー受信者のメッセージ受信の順序に対応します(メッセージの有効期限、および新しい、優先度の高いメッセージの到着に影響されます)。
永続的サブスクライバは、持続トピックメッセージを受信するときに使用されます。普通の一時トピックサブスクライバは、JMSプロバイダまたはサブスクライバ自体がクラッシュすると持続することができないため、トピックのサブスクライバが一時サブスクライバだけの場合、JMSプロバイダは通常、持続トピックメッセージを保持しません。
これは、サブスクライバがいない場合、トピックはメッセージを保持しないからです。発行/購読メッセージングでは、サブスクライバは、サブスクライブ後にトピックにより受信されたメッセージだけを取得します。そのため、接続がクラッシュ時に保持されない場合、持続メッセージという概念は存在しません。
永続的サブスクライバは、クラッシュ時でも持続でき、サブスクライブは、明示的に解除されるまで失われません。永続的サブスクライバが一時的に使用できない場合、JMSプロバイダは、メッセージをバッファに入れます。サブスクライバが再び使用可能になり、再接続すると、サブスクライバは、バッファに入れられたメッセージをすべて受信します。
永続的サブスクライバには、接続クライアントIDが必要です。 このIDはサブスクリプション名の一部で、ConnectionでsetClientID
メソッドを使用して設定する必要があります。例外リスナのように、これは、各接続に一度設定され、クライアントIDは、その接続内でのすべての永続的サブスクライバに適用されます。
メッセージセレクタは、JMSプロバイダにより呼び出されるオブジェクトで、特定のメッセージ条件を満たさないメッセージの配信を制限します。メッセージセレクタは、メッセージヘッダフィールドおよびプロパティを検証し、これらをコンシューマにより指定されたコンテキスト文字列と比較します。
メッセージセレクタにより使用されるコンテキスト文字列は、SQL92条件式構文のサブセットに基づいた構文を使用して作成されます。JDBCに精通している場合、メッセージプロパティを列名のようにクエリできます。次の表に、一般的な値をいくつか示します。完全なリストについては、JMS仕様を参照してください。
値 | 例 |
比較演算子 | Amount <= 5 Month = 'January' |
論理演算子 | JMSPriority > 3 AND Value = 42 Width = 2 OR Height > 3 Level < 4 AND NOT Error |
算術演算子 | Amount * 22.3 + Tax / 1.45 < 4220.12 -Value * 9 < 12 |
SQL演算子 | Amount BETWEEN 12 AND 22 Quote IN ('SSSW','CSCO','MSFT') Property IS NULL Number LIKE '12%3' Word LIKE 'hel_o' |
P2Pモデルでは、選択されないメッセージはキューで保持されます。このため、コンシューマにより選択されなかったメッセージをJMSプロバイダが別のコンシューマに再割り当て(または今後のコンシューマのためにキューに保持)できます。
発行/購読モデルでは、選択されないメッセージは破棄されます。このため、サブスクライバ側では、トピックにメッセージが送信されていないように見えます。メッセージは、トピックの他のサブスクライバが選択することもできます。