Spring Boot构建动态定时任务

前言

前阵子,有动态定时任务的需求,工期紧张且项目中未引入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;
    }

如此,就实现了动态设置间隔秒数的定时任务。

posted @ 2020-09-09 16:16  从此寂静无声  阅读(1625)  评论(0编辑  收藏  举报