1

TomcatにデプロイするWebアプリケーションを開発しています。Tomcatが起動したら、サーブレット(web.xml内)を使用してJavaクラスを呼び出します。

<web-app>
    <display-name>Consumer</display-name>
    <servlet>
        <servlet-name>start</servlet-name>
        <servlet-class>com.test.sample.Consumer</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
</web-app>

私のConsumer.javaは、AMQPサーバーのキューにサブスクライブします。while (true)これは、スタンドアロンのJavaプログラムで正常に機能するループを使用して実現します。これはWebアプリケーションのコンテキストでも機能しますが、Tomcatサーバー(NetBeans IDE内)を停止することはできず、whileループが原因であると考えています。ここにいくつかのコードがあります:

public class Consumer {
    public Consumer()
        consume();
    }

    private void consume()

        ...

        while (true) {
            // Await incoming messages from queue
            // Process message
        }

    }

}

これを処理するためのより良い方法はありますか?または、ループから抜け出すために停止を通知しますか?

ありがとう!


ServletContextListenerを使用するように更新されました:

public final class ApplicationListener implements ServletContextListener {

    private ScheduledExecutorService scheduler;

    public ApplicationListener() {
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        System.out.println("***** Stopping Consumer *****");
        scheduler.shutdownNow();
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {

        System.out.println("***** Starting Consumer *****");

        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new ScheduledConsumer(), 0, 15000, TimeUnit.MILLISECONDS);

    }

    public class ScheduledConsumer implements Runnable {
        @Override
        public void run() {
            Consumer k = new Consumer();
            k.consumeOnce();
        }
    }
}
4

2 に答える 2

3

いくつか提案がありますが、コンテナー環境をより適切に操作するには、アーキテクチャーを少し変更する必要があります。

サーブレットコンテナは、さまざまなイベントの通知を受け取ることができる「リスナー」をサポートします。具体的には、そのうちの1つはServletContextListener、コンテキスト(別名webapp)が(メソッドを介して)サービスを開始するときと(contextInitializedメソッドを介して)サービスを停止するときに通知を受け取るものcontextDestroyedです。

私の推奨事項は、次のことを行うことです。

  1. クラスのコンストラクターを変更して、Consumer自動的に呼び出されないようにしますconsume()。代わりに、のようなパブリックメソッドを追加し、consumeOnceそのレベルでループをまったく使用しないでください
  2. フラグだけでなく、メンバーとしてaと参照ServletContextListenerを持つaを記述します。その中で、新しいオブジェクトを作成してから、次のような新しい(デーモン)スレッドを起動する 必要があります。ConsumerThreadvolatile boolean stopcontextInitializedConsumer
    • 呼び出しConsumer.consumeOnce
    • Thread.sleep適切な時間の呼び出し
    • 停止フラグが真になるまで、前の2つのステップをループします
  3. ServletContextListenerのメソッドcontextDestroyedに停止フラグを設定して、実行中のスレッドtrueを呼び出します。Thread.interrupt

正確な詳細が欠けていると思いますが、それが一般的な考え方です。Tomcatがシャットダウンすると、コードにシャットダウンが通知され、独自のループスレッドをクリーンに終了できます。Consumerシグナルを受け取ったときに中止されない場合は、消費するものをすべて消費する試みを中止する方法を提供する必要がある場合があります(たとえば、空のキューからオブジェクトをプルするのを待つのをやめる) Thread.interrupt。(たとえばObject.wait()、モニター通知を待機するためにを使用する場合は、永久にブロックされないように、タイムアウト付きの待機を使用するように変更する必要があります)。

于 2013-01-05T14:45:16.540 に答える
-2

ループを含むコードを別のスレッドに配置し、コンシューマーからスレッドを開始する必要があります。

private void consume() {
  Thread x = new Thread(new Runnable() {
    @Override
    public void run() {
      while(true) {
      ....
      }
   });
   x.start();
}
于 2013-01-04T20:42:05.480 に答える