JMS を使用するエンタープライズ・アプリケーションの設計
非同期メッセージングに JMS API を直接使用するエンタープライズ・アプリケーションを設計する 場合には、多数の考慮事項があります。
手順
- メッセージング操作の場合は、Sun の javax.jms パッケージで定義されているインターフェースへの参照のみを使用するアプリケーション・プログラムを作成する必要があります。 JMS は、基礎となるトランスポートにマップするメッセージングの一般的なビューを定義します。 JMS を使用するエンタープライズ・アプリケーションは、 Sun の javax.jms パッケージで定義されている以下のインターフェースを利用します。
- 接続
- 基礎となるトランスポートへのアクセスを提供し、Session の作成に使用されます。
- Session
- メッセージを作成および利用するためのコンテキストを提供します。MessageProducers および MessageConsumers の作成に使用されるメソッドも含みます。
- MessageProducer
- メッセージの送信に使用します。
- MessageConsumer
- メッセージの受信に使用します。
一般的な JMS インターフェースは、Point-to-Point およびパブリッシュ/サブスクライブの振る舞いに関して、以下のような、より詳細なバージョンにサブクラス化されます。表 1. JMS 共通インターフェースの Point-to-Point バージョンおよびパブリッシュ/サブスクライブ・バージョン. この表の 1 列目には JMS 共通インターフェースがリストされており、2 列目には対応する Point-to-Point インターフェースがリストされ、3 列目には対応するパブリッシュ/サブスクライブ・インターフェースがリストされています。 JMS 共通インターフェース Point-to-Point インターフェース パブリッシュ/サブスクライブ・インターフェース ConnectionFactory QueueConnectionFactory TopicConnectionFactory 接続 QueueConnection TopicConnection 宛先 キュー トピック Session QueueSession、 TopicSession、 MessageProducer QueueSender TopicPublisher MessageConsumer QueueReceiver、
QueueBrowserTopicSubscriber これらの JMS インターフェースの使用について詳しくは、Java™ Message Service Documentation および IBM MQ インフォメーション・センターの『Java の使用』セクションを参照してください。
J2EE specification のセクション『Java Message Service (JMS) Requirements』には、Web コンテナーおよび EJB コンテナーで呼び出してはならないメソッドのリストが記載されています。javax.jms.Session method setMessageListener javax.jms.Session method getMessageListener javax.jms.Session method run javax.jms.QueueConnection method createConnectionConsumer javax.jms.TopicConnection method createConnectionConsumer javax.jms.TopicConnection method createDurableConnectionConsumer javax.jms.MessageConsumer method getMessageListener javax.jms.MessageConsumer method setMessageListener javax.jms.Connection setExceptionListener javax.jms.Connection stop javax.jms.Connection setClientID
このメソッドの使用制限に反すると、WebSphere® Application Server により javax.jms.IllegalStateException 例外がスローされます。
- アプリケーションは、管理対象オブジェクトとして、WebSphere Application Server に事前定義された JMS リソースを参照します。
エンタープライズ・アプリケーションが使用する JMS リソースの詳細は、WebSphere Application Server に定義され、WebSphere 管理サポートによって JNDI 名前空間にバインドされます。エンタープライズ・アプリケーションは、実装に関する知識がなくても、JNDI 名前空間からこれらのオブジェクトを検索し、使用することができます。 この結果、エンタープライズ・アプリケーションを変更しなくても、JMS リソースが定義した、基礎となるメッセージング・アーキテクチャーを変更できるようになります。
表 2. Point-to-Point およびパブリッシュ/サブスクライブ・メッセージングの JMS リソース. この表の 1 列目には Point-to-Point メッセージング用の JMS リソースがリストされており、2 列目にはパブリッシュ/サブスクライブ用の JMS リソースがリストされています。 Point-to-Point Publish/Subscribe ConnectionFactory (または QueueConnectionFactory)
キューConnectionFactory (または TopicConnectionFactory)
トピック接続ファクトリーは、JMS プロバイダーからメッセージング・システムへの接続を作成するために使用され、接続を作成するために必要な構成パラメーターをカプセル化します。
- パフォーマンス向上のために、アプリケーション・サーバーは、JMS プロバイダーとの接続およびセッションをプールします。 アプリケーションでは、接続とセッションのプール・プロパティーを適切に構成する必要があります。そうしないと、接続とセッションが期待通りに動作しない場合があります。
- アプリケーションでは、JMS 接続、セッション、プロデューサー、またはコンシューマーをキャッシュに入れてはいけません。 Bean またはサーブレットが完了すると、WebSphere Application Server はこれらのオブジェクトを閉じるため、キャッシュされたオブジェクトを使用しようとしても、javax.jms.IllegalStateException 例外により失敗します。
パフォーマンス向上のために、アプリケーションは JNDI から検索された JMS オブジェクトをキャッシュできます。例えば、EJB またはサーブレットは JMS ConnectionFactory を 1 度のみ検索する必要がありますが、インスタンス生成ごとに createConnection メソッドを呼び出す必要があります。 JMS プロバイダーを使用した接続およびセッションに対するプールの効果により、パフォーマンスへの影響はありません。
- 非永続サブスクライバーは、そのサブスクライバーが作成されたときに存在していたものと同じトランザクション・コンテキスト (例えば、グローバル・トランザクションまたは指定解除されたトランザクション・コンテキスト) でしか使用できません。
- デフォルトのメッセージング・プロバイダーで永続サブスクリプションを使用します。 JMS トピック上の永続サブスクリプションにより、サブスクライバーがそのサーバーに接続されていない期間の後でも、サブスクライバーは、そのトピックにパブリッシュされるすべてのメッセージのコピーを受け取ることができます。
このため、サブスクライバー・アプリケーションは長期間サーバーと切断された状態で稼働することができ、その後サーバーに再接続して、接続されていなかった期間にパブリッシュされたメッセージを処理できます。
アプリケーションが永続サブスクリプションを作成する場合、これは、
管理者が管理コンソールを介して表示および処理できるランタイム・リストに追加されます。
各永続サブスクリプションには、固有 ID clientID##subName が指定されます。各部の意味は次のとおりです。
- clientID
- 接続およびそのオブジェクトを、(JMS プロバイダーのクライアントとして) アプリケーション用に保守されたメッセージと関連付けるために使用されるクライアント ID。ランタイム管理のために、永続サブスクリプションを関連アプリケーションと関連付ける必要がある場合は、アプリケーションの識別に役立つ命名規則を使用する必要があります。
- subName
- 指定されたクライアント ID 内の永続サブスクリプションを一意的に識別するために使用されるサブスクリプション名。
メッセージ駆動型 Bean が作成する永続サブスクリプションの場合、これらの値は JMS アクティベーション・スペックで設定されます。その他の永続サブスクリプションの場合、 クライアント ID は JMS 接続ファクトリーで設定され、サブスクリプション名は createDurableSubscriber オペレーション上でアプリケーションによって設定されます。
トピックに対する永続サブスクリプションを 作成するために、アプリケーションは JMS API で定義される createDurableSubscriber オペレーションを使用します。public TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String subName, java.lang.String messageSelector, boolean noLocal) throws JMSException
- トピック (topic)
- サブスクライブする JMS トピックの名前。これは、適切な JNDI 項目のルックアップなどによって検出され、 javax.jms.Topic インターフェースをサポートするオブジェクトの名前です。
- subName
- このサブスクリプションを識別するために使用される名前。
- messageSelector
- メッセージ・セレクター式と一致するプロパティーを持つメッセージのみが、コンシューマーに配信されます。 ヌルの値または空ストリングは、すべてのメッセージが配信されることを示します。
- noLocal
- true に設定されている場合、このパラメーターにより、永続サブスクライバーと同じ接続でパブリッシュされるメッセージは配信されなくなります。
アプリケーションは、topic パラメーターおよび subName パラメーターのみを取る createDurableSubscriber の 2 つの引数形式を使用することができます。この代替呼び出しは、 上記の 4 つの引数バージョンを直接呼び出しますが、messageSelector をヌルに設定し (すべてのメッセージが配信される)、noLocal を false に設定します (この接続でパブリッシュされたメッセージが配信される)。例えば、mySubscription というサブスクリプション名で、 myTopic と呼ばれるトピックに対して永続サブスクリプションを作成するには、次のようにします。session.createDurableSubscriber(myTopic,"mySubscription");
createDurableSubscription オペレーションが失敗した場合は、メッセージを提供する JMS 例外、およびリンクされた例外がスローされ、問題の原因についての詳細を示します。
永続サブスクリプションを削除するために、アプリケーションは JMS API で定義される非サブスクライブ・オペレーションを使用します。
通常の操作では、永続サブスクリプションのアクティブな (接続された) サブスクライバーは同時に 1 つしかありません。ただし、サブスクライバー・アプリケーションは、フェイルオーバーおよびロード・バランシングの目的で、複製されたアプリケーション・サーバーで実行することができます。 この場合、"1 つのアクティブ・サブスクライバー"の制限は、複数の同時コンシューマーを持つことができる共有永続サブスクリプションを提供するために解除されます。
アプリケーションによる永続サブスクリプションの使用について詳しくは、JMS 仕様のセクション『Using Durable Subscriptions』を参照してください。
- 必要なメッセージ・セレクターを決定します。 JMS メッセージ・セレクターのメカニズムを使用して、キュー上のメッセージのサブセットを選択し、そのサブセットが受信呼び出しにより戻されるようにすることができます。 セレクターは、JMS メッセージ・ヘッダー内のフィールドとメッセージ・プロパティー内のフィールドを参照することができます。
- 受信したメッセージに基づいた処理をします。 メッセージを受信すると、アプリケーションのビジネス・ロジックに必要な処理を行うことができます。
一般的な JMS アクションの中には、メッセージが正しいタイプであるかどうかを検査し、そのメッセージの内容を抽出するものがあります。
メッセージの本文から内容を抽出するには、一般的な Message クラス (受信メソッドの宣言済みの戻りの型) から、TextMessage などの、より特化されたサブクラスへキャストします。
キャストする前に必ずメッセージ・クラスをテストすることをお勧めします。
そうすることで、予期しないエラーを慌てずに処理することができます。
この例では、instanceof オペレーターは、 受信したメッセージが TextMessage タイプであるかどうかを検査するために使用されます。 検査の後で、メッセージの内容は、TextMessage サブクラスへキャストすることによって抽出されます。
if ( inMessage instanceof TextMessage ) ... String replyString = ((TextMessage) inMessage).getText();
- デフォルト・メッセージング・プロバイダーを使用している JMS アプリケーションは、WebSphere Application Server バージョン 5 の組み込みメッセージングまたは IBM MQ から受け取ったメッセージの内容に、制限なしでアクセスすることができます。
- JMS アプリケーションは、JMS_IBM* プロパティーの完全なセットにアクセスすることができます。 これらのプロパティーは、デフォルトのメッセージング・プロバイダー、V5 デフォルト・メッセージング・プロバイダー、または IBM MQ プロバイダーで提供されるリソースを使用する JMS アプリケーションにとって重要です。
IBM MQ によって処理されるメッセージの場合、JMS_IBM* プロパティーは同等の IBM MQ Message Descriptor (MQMD) フィールドにマップされます。JMS_IBM* プロパティーおよび MQMD フィールドについて詳しくは、IBM MQ インフォメーション・センターの『Java の使用』セクションを参照してください。
- JMS アプリケーションでは、送信操作の結果およびそれらのメッセージの結果に関するリモート・フィードバックをプロデューサーに提供するために、レポート・メッセージを管理対象要求/応答処理の形で使用できます。 JMS アプリケーションは、JMS_IBM_Report_Xxxx メッセージ・プロパティーを使用するレポート・オプションの全範囲を要求することができます。 JMS レポート・メッセージの使用について詳しくは、JMS レポート・メッセージを参照してください。
- JMS アプリケーションは JMS_IBM_Report_Discard_Msg プロパティーを使用して、
要求メッセージを宛先キューに配信することができない場合に、その廃棄方法を制御することができます。
- MQRO_Dead_Letter_Queue
- これはデフォルトです。 要求メッセージは、送達不能キューに書き込まれます。
- MQRO_Discard
- 要求メッセージは廃棄されます。これは通常、配信不能な要求メッセージを送信側に戻すために MQRO_Exception_With_Full_Data と一緒に使用されます。
- リスナーを使用して、非同期にメッセージを受信します。 サーブレットまたはエンタープライズ Bean ではなく、クライアントで、
QueueReceiver.receive() への呼び出しに代わる方法は、適切なメッセージが使用可能になると自動的に呼び出されるメソッドを登録することです。
以下に例を示します。
... MyClass listener =new MyClass(); queueReceiver.setMessageListener(listener); //application continues with other application-specific behavior. ...
メッセージが使用可能になると、リスナー・オブジェクト上の onMessage() メソッドがそれを検出します。import javax.jms.*; public class MyClass implements MessageListener { public void onMessage(Message message) { System.out.println("message is "+message); //application specific processing here ... } }
非同期メッセージ配信の場合、アプリケーション・コードは、メッセージの受信に失敗したことにより発生した例外をキャッチできません。 これは、アプリケーション・コードが receive() を明示的に呼び出さないことが原因です。 この状態を処理するために、ExceptionListener を登録することができます。 これは、onException() を実装するクラスのインスタンスです。 エラーが発生すると、このメソッドは、 このメソッドの唯一のパラメーターとして渡される JMSException により呼び出されます。
メッセージを非同期的に受信するリスナーの使用の詳細については、Java Message Service Documentation を参照してください。
注: 独自の JMS リスナー・クラスを開発する代わりに、メッセージ駆動型 Bean を使用できます。詳しくは、メッセージ駆動型 Bean を使用するためのプログラミングに記載されています。 JMS receive() 呼び出しが、 同じサーバーにデプロイされている別のアプリケーション・コンポーネントによって生成されるメッセージを待っている場合は、 この receive() をサーバー・サイドのアプリケーション・コンポーネントから実行する際に気を付けてください。 このような JMS receive() は同期するため、応答メッセージを受信するまでブロックされます。
このタイプのアプリケーション設計では、ワーク・スレッドがすべて、応答待ちでブロックされている受信コンポーネントによって使い尽くされ、JMS 応答メッセージを生成するアプリケーション・コンポーネントをディスパッチするために使用可能なワーカー・スレッドが残されていない状態になる可能性があり、コンシューマーまたはプロデューサーの問題につながるおそれがあります。例えば、サーブレット Bean とメッセージ駆動型 Bean は、 同じサーバーにデプロイされます。このサーブレットは、要求をディスパッチする際に、メッセージ駆動型 Bean で処理されるキューにメッセージを送信します (つまり、サーブレットによって生成されるメッセージは、メッセージ駆動型 Bean の onMessage() メソッドによって取り込まれます)。 サーブレットは、続いて、receive() を発行して、 一時 ReplyTo キューで応答を待ちます。 メッセージ駆動型 Bean の onMessage() メソッドは、データベース照会を実行し、一時キュー上のサーブレットに応答を戻します。 (サーバー・ワーカー・スレッド数と比べて) 1 度に多数のサーブレット要求が発生した場合は、使用可能なすべてのサーバー・ワーカー・スレッドを使用して、サーブレット要求のディスパッチ、メッセージの送信、および応答の待機を行うことになる可能性があります。 アプリケーション・サーバーは、 現在保留中であるメッセージ駆動型 Bean を処理するスレッドが残されていない状態になります。 したがって、サーブレットが待機中の応答はすべてブロックされるため、サーバーが停止し、アプリケーション障害となる可能性があります。
解決策としては以下のことが考えられます。
- ワーカー・スレッド数 (サーバー領域当たりのスレッド数 * サーバー当たりのサーバー領域数) が、 receive() を実行するアプリケーション・コンポーネントの並行ディスパッチ数より大きくなるようにして、 メッセージ生成コンポーネントをディスパッチするのに使用できるワーカー・スレッドが、 常に存在するようにしてください。
- 受信側アプリケーション・コンポーネントが、プロデューサー・アプリケーション・コンポーネントとは別のサーバーに配置される、アプリケーション・トポロジーを使用します。 このようなデプロイ・シナリオの下でワーカー・スレッドの使用について慎重に考慮する必要性が残っている場合でも、このように分離することで、メッセージ受信コンポーネントでブロックできないスレッドが常に確保されます。 複数のアプリケーションがインストールされているアプリケーション・サーバーなど、その他にも考慮すべき対話式処理が存在する可能性があります。
- クライアント・コンポーネントからメッセージ受信を実行するようにアプリケーションをリファクタリングしてください。クライアント・コンポーネントは、ワーカー・スレッド用のプロデューサー・コンポーネントとは競合しません。 さらに、クライアント・コンポーネントでは、J2EE サーバーで禁止されている非同期 (非ブロッキング) 受信が可能です。 したがって、例えば上記のアプリケーション例では、クライアントがメッセージをキューに送信し、MDB からの応答を待つようにリファクタリングできます。
- IBM MQ またはバージョン 5 組み込みメッセージング・サポートで認証を使用する場合は、12 文字よりも長いユーザー ID を使用することはできません。 例えば、デフォルトの Windows NT ユーザー ID administrator は 13 文字なので、WebSphere 内部メッセージングには使用できません。
- EJB 仕様で定義されているように、createxxxSession 呼び出しでのフラグの使用には以下の点が当てはまります。
- createxxxSession で渡されるトランザクション処理済みのフラグは、グローバル・トランザクション内では無視され、すべての作業がトランザクションの一環として実行されます。 トランザクション外ではトランザクション処理済みフラグが使用されます。フラグが true に設定されている場合、アプリケーションは session.commit() および session.rollback() を使用して、作業の完了を制御する必要があります。 EJB2.0 モジュールでは、トランザクション処理済みフラグが true に設定されており、XA トランザクションの外側にある場合、セッションは WebSphere ローカル・トランザクションに関与し、メソッドの未解決のアクション属性は、アプリケーションによってコミットまたはロールバックされない限り、JMS 作業に適用されます。
- クライアントは、Message.acknowledge() を使用してメッセージを確認することはできません。createxxxSession 呼び出しで CLIENT_ACKNOWLEDGE の値が渡されると、メッセージは、アプリケーション・サーバーによって自動認識され、Message.acknowledge() は使用されません。
- アプリケーションで IBM MQ を外部 JMS プロバイダーとして使用する場合、コンテナー管理トランザクション内でメッセージを送信します。
IBM MQ を外部 JMS プロバイダーとして使用する場合、ユーザー管理トランザクション内で送信されるメッセージは、トランザクションがコミットする前に到着する場合があります。これが起こるのは、IBM MQ を外部 JMS プロバイダーとして使用し、ユーザー管理トランザクション内でメッセージを IBM MQ キューに送信する場合だけです。メッセージは、トランザクションがコミットする前に宛先キューに到着します。
この問題の原因は、IBM MQ リソース・マネージャーがユーザー管理トランザクション内で確立されていないことです。
この問題は、コンテナー管理トランザクションを使用すると解決します。


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tmj_desap
ファイル名:tmj_desap.html