Spring调度任务 – 只运行一次

是否可以在指定的时间仅安排一次Spring服务方法? 例如,当前时间是下午2点,但是当我点击操作按钮时,我希望我的服务方法在晚上8点开始。 我熟悉@Scheduled注释,我不知道如何编写cron表达式而不是定期运行。 这个@Scheduled(cron = "0 0 20 * * ?")每天晚上8点开火。
有什么建议么?

您可以使用Spring的TaskScheduler实现之一。 我在下面提供了一个示例,其中一个不需要太多配置(ConcurrentTaskScheduler包装单线程预定执行程序)。

最简单的方法是一个名为schedule的方法 ,它只采用Runnable和Date。 这将导致任务 指定时间 后运行一次 。 所有其他方法都能够安排任务重复运行。

阅读有关任务执行和计划的更多信息

简单的工作示例:

 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类之一


更新 – 取消计划任务

TaskScheduler的schedule方法返回ScheduledFuture,这是一个可以取消延迟结果操作

因此,为了取消它,您需要保留计划任务的句柄(即保留ScheduledFuture返回对象)。

对上述代码的更改取消任务:

  1. 在executeTaskT方法之外声明ScheduledFuture。 private ScheduledFuture scheduledFuture;

  2. 将您的调用修改为schedule以保持返回对象: scheduledFuture = scheduler.schedule(exampleRunnable, new Date(1432152000000L));

  3. 在您的代码中的某个地方调用scheduledFuture对象boolean mayInterruptIfRunning = true; scheduledFuture.cancel(mayInterruptIfRunning); boolean mayInterruptIfRunning = true; scheduledFuture.cancel(mayInterruptIfRunning);

为了不在每次方法调用时创建ScheduledExecutorServiceConcurrentTaskScheduler ,在创建服务时初始化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; } }