由于业务需求,需要提供一个能够让用户动态配置定时任务的入口,定时去同步数据

1、简单的业务处理,直接使用@Scheduled注解就能开启定时任务,例如在方法上@Scheduled(cron = “0 0/1 * * * ?”),书写cron表达式就能配置定时任务。

/**
* 每分钟触发一次
*/
@Scheduled(cron = "0 0/1 * * * ?")
public void execEveryDay() {
checkPlan();
}

2、但是随着业务复杂化,使用注解目前是满足不了动态配置定时任务的,以下代码能够实现cron表达式的动态配置。

第一步,在启动类新增注解@EnableScheduling

@SpringBootApplication
@EnableScheduling
public class testApplication {
public static void main(String[] args) {
SpringApplication.run(testApplication .class, args);
}

}

第二步,编写定时任务类

@Lazy(false)
@Component
@EnableScheduling
@Slf4j
public class OutPutTask implements SchedulingConfigurer {
// 默认的cron表达式
private String cron = "0 55 23 ? * *";

// 定时任务的执行顺序:由上而下按顺序执行,当服务启动时或者定时任务时间到了,先执行业务逻辑,再设置定时任务
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(() -> {
// addTriggerTask这一代码块用于当定时任务到了或者服务启动时,执行的业务逻辑
try {
// 分布式锁,避免高并发同时执行方法
Boolean lockStatus = redisTemplate.opsForValue().setIfAbsent(RedisKeyPrefix.RECORD_OUT_PUT, new Date(), 1, TimeUnit.MINUTES);
if (lockStatus == null || !lockStatus) {
return;
}
log.info("产能计算定时任务{}", new Date());
// 这个是自己写的自定义方法
recordOutput();
} finally {
// 释放锁
redisTemplate.delete(RedisKeyPrefix.RECORD_OUT_PUT);
}
}, triggerContext -> {
// 此代码块用于动态拿到cron表达式并设置定时任务,当定时任务时间到了,就会重新获取cron表达式,重新设置定时任务
cron = this.getCronString();
CronTrigger trigger;
try {
// 一旦设置,立即生效
trigger = new CronTrigger(cron);
return trigger.nextExecutionTime(triggerContext);
} catch (Exception e) {
// 如果格式有问题就按默认时间(时间为每天23点55分)
trigger = new CronTrigger("0 55 23 ? * *");
return trigger.nextExecutionTime(triggerContext);
}
});
}

/**
* 拿到cron表达式
*/
private String getCronString() {
// 获取时间(当前方法返回的时间格式为yyyy-MM-dd HH:mm:ss)
Date beginDate = dictService.getDayOutputBeginTime(new Date());
// 截取分钟和小时
String hour = beginDate.toString().substring(11, 13);
String min = beginDate.toString().substring(14, 16);
// 替换min,hour
String cron = "0 min hour ? * *";
return cron.replaceAll("min", min).replaceAll("hour", hour);
}

然后我们只需要在页面上提供一个能够让用户配置定时任务的入口或者在数据库里配置cron表达式,就能实现动态配置。
如果面向的用户懂得cron表达式,也可以直接让用户配置cron表达式也是可以的,省的程序员进行额外的数据处理,只要配置正确,任何处理方式都行,例如:

点击确定后,会更新数据库,当定时任务时间到了,就会触发定时任务机制,重新设置定时任务