前言
前阵子,有动态定时任务的需求,工期紧张且项目中未引入Quartz
。
此时,似乎只剩下Spring Boot提供的定时任务可以考虑了。
调研
Spring Boot中定时任务,一般是使用@Scheduled
注解进行标注,可以设置对应的cron
表达式或者设置运行间隔周期。
样例代码如下所示:
@Scheduled(cron="0/5 * * * * ?")
void testPlaceholder1() {
System.out.println("Execute at " + System.currentTimeMillis());
}
不过使用注解标注定时任务,无法满足定时任务周期定时更新的需求。
解救
查询资料,发现可以使用继承SchedulingConfigurer
接口,实现动态定时任务。
@Slf4j
@Configuration
public class ImepStatusSchedulingConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
()->{
// 业务逻辑
},
triggerContext -> {
// 此处,cron表达式从数据库查询得到
String cron = cronMapper.getCron();
// 根据cron表达式,构建CronTrigger,计算下一次的执行时间
CronTrigger trigger = new CronTrigger(cron);
return trigger.nextExecutionTime(triggerContext);
}
);
}
}
由代码可知,每次运行定时任务时,均会动态计算下一次的运行时间点。
改动
Cron表达式比较复杂(项目由多人维护),而需求里只要求支持间隔固定秒数执行任务。
因此CronTrigger
不再适合,因此需要进行相应改动。改动如下所示:
// 出于篇幅,此处省略无关代码
triggerContext -> {
// 此处,duration可以从数据库查询得到
int duration = 1;
Date date = triggerContext.lastCompletionTime();
if (date != null) {
Date scheduled = triggerContext.lastScheduledExecutionTime();
if (scheduled != null && date.before(scheduled)) {
// Previous task apparently executed too early...
// Let's simply use the last calculated execution time then,
// in order to prevent accidental re-fires in the same second.
date = scheduled;
}
} else {
date = new Date();
}
date.setTime(date.getTime() + duration * 1000);
return date;
}
如此,就实现了动态设置间隔秒数的定时任务。