正確に指定された時間に一度だけSpringサービスメソッドをスケジュールすることは可能ですか?たとえば、現在の時刻は午後2時ですが、アクションボタンを押すと、サービスメソッドが午後8時に開始されます。私は@Scheduledアノテーションに精通しており、定期的に実行しないようにcron式を記述する方法がわかりません。この@Scheduled(cron = "0 0 20 * * ?")
は毎日午後8時に起動します。
助言がありますか?
SpringのTaskSchedulerの実装のいずれかを使用できます。あまり多くの構成を必要としない例(シングルスレッドのスケジュールされたエグゼキューターをラップするConcurrentTaskScheduler)を使用して、以下の例を提供しました。
最も単純なメソッドは、RunnableとDateのみを使用するscheduleという名前のメソッドです。これにより、タスクは指定時間の後に1回実行されます。他のすべての方法では、タスクを繰り返し実行するようにスケジュールできます。
タスクの実行とスケジューリング の詳細を読む
簡単な作業例:
private TaskScheduler scheduler;
Runnable exampleRunnable = new Runnable(){
@Override
public void run() {
System.out.println("Works");
}
};
@Async
public void executeTaskT() {
ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor();
scheduler = new ConcurrentTaskScheduler(localExecutor);
scheduler.schedule(exampleRunnable,
new Date(1432152000000L));//today at 8 pm UTC - replace it with any timestamp in miliseconds to text
}
...
executeTaskT() //call it somewhere after the spring application has been configured
注:
@Scheduledおよび@Asyncアノテーションのサポートを有効にするには、@ EnableSchedulingおよび@EnableAsyncをいずれかの@Configurationクラスに追加します
Update -スケジュールされたタスクのキャンセル
TaskSchedulerのスケジュールメソッドは、ScheduledFutureを返します。ScheduledFutureは、キャンセル可能な遅延結果を含むアクションです。
そのため、キャンセルするには、スケジュールされたタスクへのハンドルを保持する必要があります(つまり、ScheduledFuture戻りオブジェクトを保持します)。
タスクをキャンセルするための上記のコードへの変更:
private ScheduledFuture scheduledFuture;
scheduledFuture = scheduler.schedule(exampleRunnable,
new Date(1432152000000L));
boolean mayInterruptIfRunning = true;
scheduledFuture.cancel(mayInterruptIfRunning);
デッドマンの解決策:
@Scheduled(initialDelay = 1000 * 30、fixedDelay = Long.MAX_VALUE)
あなたはそれが再び発火する前に死んでしまいます。
すべてのメソッド呼び出しでScheduledExecutorService
とConcurrentTaskScheduler
を作成しないようにするには、サービスの作成時にTaskScheduler
を初期化するのが便利です。
private final TaskScheduler taskScheduler =
new ConcurrentTaskScheduler(Executors.newScheduledThreadPool(10));
@Async
はタスクをスケジュールしてメソッドを終了するだけなので意味がありません。
PeriodicTriggerは次のように拡張できます。lastCompletionTimeをチェックします。タスクが以前に実行されたことがない場合はnullになります。特定の時間に一度だけタスクを実行する場合は、このバリエーションを試すことができます。
class RunOnceTrigger extends PeriodicTrigger {
public RunOnceTrigger(long period) {
super(period);
setInitialDelay(period);
}
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
if(triggerContext.lastCompletionTime() == null) { // hasn't executed yet
return super.nextExecutionTime(triggerContext);
}
return null;
}
}