目录
在一些业务场景中,我们需要定义一些任务在我们指定的时间或是每隔一个时间段就自动执行,来作为任务的前提,保证业务的执行。比如:我们需要一个定时任务,每天早上6点执行,对数据库中的某个日期字段进行修改,修改为当天时间。
1.静态定时任务
springboot中为我们提供了自带的定时任务。
首先,我们需要让项目能使用定时任务:
@EnableScheduling
@SpringBootApplication
public class CourtSeckillMain {
public static void main(String[] args) {
SpringApplication.run(CourtSeckillMain.class,args);
}
}
然后,我们需要在业务类中编写代码:
@Override
@Scheduled(cron = "0 0 6 * * ?")
//秒 分 时 日 月 周 年(可选);*表所有可能的值,-指定范围值,/表示步长
public void doScheduleTask(){
log.info("执行定时任务");
//这里是你的业务逻辑
}
上述代码称为静态定时任务,主要依靠 @Scheduled 标签实现,根据其参数cron表达式每隔时间间隔自动执行任务。
cron参数:cron表达式中可填6个值,分别对应 秒 分 时 日 月 周 年。* 表所有可能的值,- 指定范围值,/ 表示步长,?表示不指定值即该值不影响。
0 0 6 * * ? 表示每天6点执行任务
0/5 * * * * ? 表示每5秒执行一次任务
0 * 6 * * ? 表示每天的6点-7点之间的每一分钟都执行一次
0 * 6-8 * * ? 表示每天的6点-9点之间的每一分钟都执行一次
5 10 6 * * ? 表示每天的6:10:05执行一次
0 10,44 14 ? 3 WED 表示三月的每周三的14:10和14:44触发
静态定时任务通过 @Scheduled 标签指定好执行时间,从而执行定时任务,使用较为方便但不太灵活,指定好执行时间后则无法更改。
2.动态定时任务
如果我们需要动态修改定时任务的cron值,我们可以通过继承 SchedulingConfigurer 类来实现:
@Data
@Slf4j
@Component
@ConfigurationProperties(prefix = "scheduled.task")
public class ScheduleTask implements SchedulingConfigurer {
private String cron;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(() -> {
// 业务代码
log.info("定时任务,currentTime:{}", LocalDateTime.now());
}, triggerContext -> {
// 使用CronTrigger触发器,可动态修改cron表达式来操作循环规则
CronTrigger cronTrigger = new CronTrigger(cron);
return cronTrigger.nextExecutionTime(triggerContext);
});
}
}
application.yml中存放初始的cron值:
scheduled:
task:
cron: "0/5 * * * * ?" #每5秒执行一次
在controller中编写接口,动态修改cron值:
@RestController
@RequiredArgsConstructor
public class seckillController {
private final ScheduleTask scheduleTask;
@GetMapping("/test")
public String test(@RequestParam("cron") String cron){
scheduleTask.setCron(cron);
log.info("修改cron为:{}",scheduleTask.getCron());
return scheduleTask.getCron();
}
}
然后我们运行程序,并通过接口修改cron值:
可以看到,修改之前,每5秒执行一次定时任务;我们将cron修改为每天10点内的每分钟执行后,变成了每分钟才执行一次。
由此实现了自定义的定时任务,并由接口动态修改定时任务的执行时间。
需要注意的是:每次修改完定时任务执行时间之后,需要执行完上一次的定时任务才会让新定义的执行时间生效。
我们由 ScheduleTask.configureTasks() 方法中的上述代码 可以看到,指定下一次任务的执行间隔是由 cronTrigger.nextExecutionTime(triggerContext) 实现的,而该方法会在一次定时任务执行完结后才调用。
(ScheduleTask.configureTasks() 方法中指定定时任务执行间隔)
所以,我们在上述运行结果中看到,在10:28:30秒执行完一次定时任务,然后在10:28:32我们对cron值进行了修改,定时任务任然按照 0/5 * * * * ? 这一cron值执行了一次,然后才配置了新的cron值。
换言之,如果我们定义了任务每天6点执行,然后某一天将其修改为12点执行,springboot会在第二天的6点执行完后再将cron值修改,然后12点再执行一次。
所以会一定程度上存在重复执行的问题,如果业务需要规避,请谨慎考虑。