実際、JMSをリッスンすることが、アプリケーションサーバーの最良の理由だと思います。メッセージをリッスンするコンポーネントが必要なため、スタンドアロンのメッセージブローカーでは問題は解決しません。これを行う最良の方法は、MDBを使用することです。理論的には、SpringsMessageListenerContainerを使用できます。ただし、これにはいくつかの欠点があります。たとえば、JMSは読み取りのブロックのみをサポートしているため、Springは(Tomcatでも)完全にサポートされていない独自のスレッドを起動する必要があり、トランザクション、セキュリティ、ネーミング(JNDI)、およびクラスの読み込みを中断する可能性があります(リモーティング)。JCAリソースアダプタは、WorkManagerを介したスレッドの起動など、必要なことを自由に実行できます。おそらく、JMS(または別の宛先)のほかにデータベースが使用され、その時点でXAトランザクションとJTA、つまりアプリケーションサーバーが必要になります。
IMHOがアプリケーションサーバーに反対する最大の理由は、仕様が公開されてからサーバーが仕様を実装して最悪のバグを解決するまでに数年かかることです(これも数年かかります)。EE 7が公開される直前に、バグが完全に散らばっていないEE6サーバーが登場し始めたのは今だけです。一部のベンダーは、次のEE 7ラインですでに忙しいため、EE6ラインのバグを修正しなくなったという点でコミカルになります。
編集
最後の段落の長い説明:
多くの場所でのJavaEEは、コンテキスト情報と呼ばれるものに依存しています。サーバー/コンテナーからアプリケーションに引数として明示的に渡されるのではなく、暗黙的に「そこに」渡される情報。たとえば、セキュリティチェックの現在のユーザー。現在のトランザクションまたは接続。コードを遅延ロードしたり、オブジェクトを逆シリアル化するためにクラスを検索するための現在のアプリケーション。または、JNDIルックアップを実行するための現在のコンポーネント(servlet、EJBなど)。この情報はすべて、サーバー/コンテナがコンポーネント(servlet、EJBなど)を呼び出す前に設定するスレッドローカルにあります。独自のスレッドを作成すると、サーバー/コンテナーはそれらについて認識せず、この情報に依存するすべての機能が機能しなくなります。スポーンするスレッドでこれらの機能を使用しないことで、これを回避できる場合があります。
いくつかのリンク
http://www.oracle.com/technetwork/java/restrictions-142267.html#threads
http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html#spring-4
サーブレット3.0の仕様を確認すると、次のことがわかります。
2.3.3.3非同期処理
15-174ページのセクション15.2.2「Webアプリケーション環境」および15-176ページのセクション15.3.1「EJBTM呼び出しでのセキュリティーIDの伝搬」などのJavaEnterpriseEditionの機能は、最初の要求を実行するスレッドでのみ使用可能です。または、リクエストがAsyncContext.dispatchメソッドを介してコンテナにディスパッチされたとき。Java Enterprise Editionの機能は、AsyncContext.start(Runnable)メソッドを介して応答オブジェクトを直接操作する他のスレッドで使用できる場合があります。
これは非同期処理に関するものですが、同じ制限がカスタムスレッドにも適用されます。
public void start(Runnable r)-このメソッドにより、コンテナーは、おそらく管理対象スレッドプールからスレッドをディスパッチして、指定されたRunnableを実行します。コンテナは、適切なコンテキスト情報をRunnableに伝播する場合があります。
繰り返しますが、非同期処理ですが、同じ制限がカスタムスレッドに適用されます。
15.2.2Webアプリケーション環境
このタイプのサーブレットコンテナは、開発者によって作成されたスレッドで実行されるときにこの動作をサポートする必要がありますが、現在はそうする必要はありません。このような要件は、この仕様の次のバージョンで追加される予定です。開発者は、アプリケーションで作成されたスレッドのこの機能に依存することは、移植性がないため推奨されないことに注意してください。
移植性がないということは、一方のサーバーでは可能であるが、もう一方のサーバーでは不可能であることを意味します。
MDBの外部でJMSを使用してメッセージを受信する場合は、次の4つの方法を使用できますjavax.jms.MessageConsumer
。
#receiveNoWait()
コンテナスレッドでこれを行うことができます。ブロックされませんが、覗き見のようなものです。メッセージが存在しない場合は、を返しますnull
。これは、メッセージを聞くのにはあまり適していません。
#receive(long)
コンテナスレッドでこれを行うことができます、それはブロックします。通常、コンテナスレッドでブロック待機を実行する必要はありません。繰り返しますが、メッセージを聞くのにはあまり適していません。
#receive()
、これはおそらく無期限にブロックします。繰り返しますが、メッセージを聞くのにはあまり適していません。
#setMessageListener()
これはあなたが望むものです、あなたはメッセージが到着したときにコールバックを受け取ります。ただし、ライブラリがアプリケーションサーバーにフックできない限り、これはコンテナスレッドにはなりません。アプリケーションサーバーへのフックは、JCAを介してリソースアダプタにのみ使用できます。
そうです、それはうまくいくかもしれませんが、それは保証されておらず、壊れるかもしれないことがたくさんあります。