是否可以在指定的时间仅安排一次Spring服务方法?例如,当前时间是下午2点,但是当我点击操作按钮时,我希望我的服务方法在晚上8点开始。我熟悉@Scheduled注释,我不知道如何编写cron表达式而不是定期运行。这一个@Scheduled(cron = "0 0 20 * * ?")
每天晚上8点开火。
有什么建议?
您可以使用Spring的TaskScheduler实现之一。我在下面提供了一个示例,其中一个不需要太多配置(ConcurrentTaskScheduler包装单线程预定执行程序)。
最简单的方法是一个名为schedule的方法,它只接受Runnable和Date。这将导致任务在指定时间后运行一次。所有其他方法都能够安排任务重复运行。
阅读更多关于task execution & scheduling的信息
简单的工作示例:
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返回对象)。
更改以上代码以取消任务:
private ScheduledFuture scheduledFuture;
scheduledFuture = scheduler.schedule(exampleRunnable,
new Date(1432152000000L));
boolean mayInterruptIfRunning = true;
scheduledFuture.cancel(mayInterruptIfRunning);
中的某处调用scheduledFuture对象取消死人的解决方案:
@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;
}
}