Apache Tomcat で JSP/Servlet を使用しています。10 分ごとにメソッドを実行する必要があります。どうすればこれを達成できますか?
2 に答える
必要最小限のサーブレット コンテナである Tomcat を使用@Schedule
しているため、Java EE 仕様で推奨されている EJB を使用することはできません。あなたの最善の策は、ScheduledExecutorService
Java 1.5のjava.util.concurrent
パッケージからです。ServletContextListener
次のようなものを使用してこれをトリガーできます。
@WebListener
public class BackgroundJobManager implements ServletContextListener {
private ScheduledExecutorService scheduler;
@Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeTask(), 0, 10, TimeUnit.MINUTES);
}
@Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
SomeTask
クラスは次のようになります。
public class SomeTask implements Runnable {
@Override
public void run() {
// Do your job here.
}
}
実際に、EJB をサポートし、すべて em (Glassfish、JBoss AS、TomEE など) を備えた実際の Java EE コンテナを使用している場合は@Singleton
、メソッドで EJB を使用できます@Schedule
。このようにして、コンテナはスレッドのプールと破棄について心配します。必要なのは次の EJB だけです。
@Singleton
public class SomeTask {
@Schedule(hour="*", minute="*/10", second="0", persistent=false)
public void run() {
// Do your job here.
}
}
この方法では、コンテナー管理トランザクションを通常の方法 (@PersistenceContext
など) で透過的に使用し続けることができますが、これは不可能ScheduledExecutorService
です — エンティティ マネージャーを手動で取得し、トランザクションを手動で開始/コミット/終了する必要がありますが、とにかく、デフォルトでは、Tomcatのようなベアボーンサーブレットコンテナには別のオプションがありません。
Timer
「ライフタイム ロング」実行中の Java EE Web アプリケーションでは、を決して使用しないでください。Java EE での使用に適さない次の主要な問題があります ( Java Concurrency in Practiceから引用)。
Timer
システムクロックの変更に敏感です。そうでScheduledExecutorService
はありません。Timer
には実行スレッドが 1 つしかないため、実行時間の長いタスクが他のタスクを遅らせる可能性があります。ScheduledExecutorService
任意の数のスレッドで構成できます。TimerTask
その 1 つのスレッドを強制終了して実行時例外がスローされると、Timer
デッドになります。つまり、スケジュールされたタスクは (サーバーを再起動するまで) 実行されなくなります。ScheduledThreadExecutor
実行時例外をキャッチするだけでなく、必要に応じてそれらを処理できます。例外をスローしたタスクはキャンセルされますが、他のタスクは引き続き実行されます。
ScheduledExecutorServiceを読み取り、 ServletContextListenerによって開始する必要があります
public class MyContext implements ServletContextListener
{
private ScheduledExecutorService sched;
@Override
public void contextInitialized(ServletContextEvent event)
{
sched = Executors.newSingleThreadScheduledExecutor();
sched.scheduleAtFixedRate(new MyTask(), 0, 10, TimeUnit.MINUTES);
}
@Override
public void contextDestroyed(ServletContextEvent event)
{
sched.shutdownNow();
}
}
また、ServletContextListenerからJavaタイマーを使用することもできますが、コンテナーからスレッド リソースの制御が奪われるため、Java EE コンテナーではお勧めできません。(ScheduledExecutorService の最初のオプションが最適です)。
Timer timer = new Timer("MyTimer");
MyTask t = new MyTask();
//Second Parameter is the specified the Starting Time for your timer in
//MilliSeconds or Date
//Third Parameter is the specified the Period between consecutive
//calling for the method.
timer.schedule(t, 0, 1000*60*10);
そしてMyTask
、その implementsTimerTask
はRunnable
インターフェイスを実装するクラスであるため、run メソッドをコードでオーバーライドする必要があります。
class MyTask extends TimerTask
{
public void run()
{
// your code here
}
}