web-dev-qa-db-ja.com

Springスケジューリングタスク-1回のみ実行

正確に指定された時間に一度だけSpringサービスメソッドをスケジュールすることは可能ですか?たとえば、現在の時刻は午後2時ですが、アクションボタンを押すと、サービスメソッドが午後8時に開始されます。私は@Scheduledアノテーションに精通しており、定期的に実行しないようにcron式を記述する方法がわかりません。この@Scheduled(cron = "0 0 20 * * ?")は毎日午後8時に起動します。
助言がありますか?

24
shx

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戻りオブジェクトを保持します)。

タスクをキャンセルするための上記のコードへの変更:

  1. ExecuteTaskTメソッドの外部でScheduledFutureを宣言します。
    private ScheduledFuture scheduledFuture;
  1. 呼び出しを変更して、返されるオブジェクトをそのまま保持するようにスケジュールします。
    scheduledFuture = scheduler.schedule(exampleRunnable,
                    new Date(1432152000000L));
  1. コードのどこかで、scheduledFutureオブジェクトでキャンセルを呼び出します
    boolean mayInterruptIfRunning = true;
    scheduledFuture.cancel(mayInterruptIfRunning);
25
Laurentiu L.

デッドマンの解決策:

@Scheduled(ini​​tialDelay = 1000 * 30、fixedDelay = Long.MAX_VALUE)

あなたはそれが再び発火する前に死んでしまいます。

13
Rick Ahlander

すべてのメソッド呼び出しでScheduledExecutorServiceConcurrentTaskSchedulerを作成しないようにするには、サービスの作成時にTaskSchedulerを初期化するのが便利です。

private final TaskScheduler taskScheduler = 
              new ConcurrentTaskScheduler(Executors.newScheduledThreadPool(10));

@Asyncはタスクをスケジュールしてメソッドを終了するだけなので意味がありません。

2
GKislin

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;
    }
}
1
smishra