サーブレットベースのWebアプリケーションでバックグラウンドタスクを実行する方法


97

Javaを使用していて、アプリケーションでサーブレットを継続的に実行したいのですが、方法がわかりません。私のサーブレットには、データベース全体からのユーザーの合計数だけでなく、データベースからのユーザー数を毎日提供するメソッドがあります。そのため、サーブレットを継続して実行したいと考えています。


「継続的に走る」とはどういう意味ですか?
skaffman

1
継続的に実行するとはどういう意味ですか?アプリサーバーが実行されている限り実行されます
fmucar '14年

2
なぜ継続して実行する必要があるのか​​わかりません...「ユーザー数」が必要な場合は、サーブレットメソッドを呼び出して、それをユーザーに渡しますか?
trojanfoe 2011年

@trojanfoe実際には毎日ユーザー数を求めているので、毎日手動でサーブレットを実行する必要があるので、サーブレットを継続的に実行する代わりに、毎日サーブレットを実行する必要はありません。
pritsag 2011年

1
@pritsag:サーブレットは、バッチジョブを実行するためではなく、ユーザーリクエストを処理するために存在します。
skaffman、2011年

回答:


217

問題は、サーブレットの目的を誤解していることです。HTTPリクエストに基づいて動作することを目的としています。毎日1回だけ実行されるバックグラウンドタスクが必要な場合。

EJBは利用可能ですか?使用する@Schedule

お使いの環境がEJB(つまり、WildFly、JBoss、TomEE、Payara、GlassFishなどの実際のJava EEサーバー)をサポートしている場合は、@Schedule代わりにを使用してください。ここではいくつかの例を示します。

@Singleton
public class BackgroundJobManager {

    @Schedule(hour="0", minute="0", second="0", persistent=false)
    public void someDailyJob() {
        // Do your job here which should run every start of day.
    }

    @Schedule(hour="*/1", minute="0", second="0", persistent=false)
    public void someHourlyJob() {
        // Do your job here which should run every hour of day.
    }

    @Schedule(hour="*", minute="*/15", second="0", persistent=false)
    public void someQuarterlyJob() {
        // Do your job here which should run every 15 minute of hour.
    }

    @Schedule(hour="*", minute="*", second="*/5", persistent=false)
    public void someFiveSecondelyJob() {
        // Do your job here which should run every 5 seconds.
    }

} 

はい、それだけです。コンテナが自動的にピックアップして管理します。

EJBは使用できませんか?使用するScheduledExecutorService

環境がEJBをサポートしていない場合(つまり、実際のJava EEサーバーではなく、Tomcat、Jettyなどのベアボーンサー​​ブレットコンテナーを使用していない場合)は、を使用しますScheduledExecutorService。これはによって開始できますServletContextListener。以下はキックオフの例です。

@WebListener
public class BackgroundJobManager implements ServletContextListener {

    private ScheduledExecutorService scheduler;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
        scheduler.scheduleAtFixedRate(new SomeHourlyJob(), 0, 1, TimeUnit.HOURS);
        scheduler.scheduleAtFixedRate(new SomeQuarterlyJob(), 0, 15, TimeUnit.MINUTES);
        scheduler.scheduleAtFixedRate(new SomeFiveSecondelyJob(), 0, 5, TimeUnit.SECONDS);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        scheduler.shutdownNow();
    }

}

ジョブクラスは次のようになります。

public class SomeDailyJob implements Runnable {

    @Override
    public void run() {
        // Do your daily job here.
    }

}
public class SomeHourlyJob implements Runnable {

    @Override
    public void run() {
        // Do your hourly job here.
    }

}
public class SomeQuarterlyJob implements Runnable {

    @Override
    public void run() {
        // Do your quarterly job here.
    }

}
public class SomeFiveSecondelyJob implements Runnable {

    @Override
    public void run() {
        // Do your quarterly job here.
    }

}

java.util.Timer/の使用について考えないでくださいjava.lang.ThreadたJava EE /サーブレットベースの環境で

最後になりましたが、決して直接使用していないjava.util.Timerおよび/またはjava.lang.ThreadJava EEの中で。これはトラブルのレシピです。詳しい説明は、同じ質問に関するこのJSF関連の回答にあります:タイマーを使用してスケジュールされたタスクのためのJSF管理対象Beanでのスレッドの生成


9
@BalucSありがとうございます。あなたの解決策が私を助けてくれました。私はjavaに新しいので、私にとって初めてのScheduledExecutorServiceについて学びました。ありがとうございました。
pritsag 2011年

@BalusC:クラスUpdateCountsをweb.xmlのどこに配置する必要がありますか?
Ashwin

1
@Ashwin web.xmlは、デプロイメント記述子です。クラスUPDATECOUNTは、それが中に置かれている必要はありませんので、展開に関連していないのweb.xml
informatik01

12
aの1つの重要な問題ScheduledExecutorService:エグゼキュータですべての例外を必ずキャプチャしてください。runメソッドから例外がエスケープされると、エグゼキュータは警告なしで実行を停止します。これはバグではない機能です。ドキュメントを読んで、グーグルで勉強してください。
バジルブルク2014年

1
@Agi:scheduler.shutdownNow()例のようにが正しく呼び出されない場合に発生します。これが呼び出されない場合、スケジュールスレッドは実際に実行され続けます。
BalusC

4

タスクを定期的に実行するには、quartzのようなライブラリを使用することをお勧めします。サーブレットは実際には何をしますか?レポートを送信しますか?


はい、1日あたりに作成されたユーザーの数と、データベース内のユーザーの総数も表示されます。
pritsag 2011年

1
ふう?システムの完全なアーキテクチャについて説明できますか。道に迷いました。
Twister

@Twister imはJavaの新機能であり、ラーニングフェーズのサーブで、サーブレットについてはあまり知りません。
pritsag 2011年

問題はサーブレットではありません。あなたが話しているアプリケーションは何ですか?(ps:コメント、特に私が回答したコメントを削除するのは悪い考えです)
Twister

@twisterユーザーがアプリケーションにアクセスすると、今日作成されたユーザーの数、現在までに作成されたユーザーの数など、すべての詳細が表示されます。ユーザーが更新を取得できるように、サーブレットをバックグラウンドで継続的に実行したいと考えています。 .Iは、これは正しいexplationない自演(PS:私は、それはそのための悪いidea.sorryだった知っている。)。
pritsag

3

2つのクラスを実装し、呼び出しstartTask()の中でmain

public void startTask()
{
    // Create a Runnable
    Runnable task = new Runnable() {
        public void run() {
            while (true) {
                runTask();
            }
        }
    };

    // Run the task in a background thread
    Thread backgroundThread = new Thread(task);
    // Terminate the running thread if the application exits
    backgroundThread.setDaemon(true);
    // Start the thread
    backgroundThread.start();
}

public void runTask()
{
    try {
        // do something...         
        Thread.sleep(1000);

    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

3
これは間違いなくWebアプリケーションでそれを行う方法ではありません。代わりに@BalusCによる上記の答えを見てください。彼はここで正しいので、彼の答えはすべて信頼できると思います。
吉谷


0

複数の非jeeコンテナーが実行されている可能性がある実動システム。タスクmaamgememtにデータベースを使用するように構成できる、Quartzスケジューラーのようなエンタープライズスケジューラーを使用しないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.