Spring 框架自带任务调度功能,比如一个轻量级的Quartz,使用简单、方便,不须要依赖其余JAR包。java
只须要在项目主程序启动类上添加@EnableScheduling开启任务调度功能便可数据库
@SpringBootApplication @EnableScheduling public class LearnApplication { public static void main(String[] args) { SpringApplication.run(LearnApplication.class, args); } }
@Component public class TestTask { @Scheduled(cron = "0/10 * * * * *") public void testTask1() { System.out.println("【任务一】测试定时任务" + LocalDateTime.now()); } }
如上述,配置一个简单的定时任务只须要在调度方法上添加@Shceduled注解便可,就可使用定时任务。markdown
@Component // 开启异步支持 @EnableAsync public class TestTask { @Scheduled(cron = "0/10 * * * * *") // 方法使用异步执行,每次任务建立一个线程执行任务 @Async public void testTask1() { System.out.println("【任务一】测试定时任务" + LocalDateTime.now() + " " + Thread.currentThread().getName()); for (int i = 0; i < 20; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("【任务一】休眠" + (i + 1) + "秒测试定时任务" + LocalDateTime.now() + " " + Thread.currentThread().getName()); } } }
每每在咱们的项目调度任务中,有的场景是须要在当前任务尚未执行完毕时,就须要执行下一个定时调度任务,在这种状况下须要使用异步的方式来执行定时任务。框架
@EnableAsync开启异步支持异步
@Async标记任务使用异步执行(下次任务将在下一个配置时间开始,不等待当前任务执行完毕)ide
当咱们编写定时任务是,流程大体为:编码->配置执行周期->启动服务。测试
当前咱们配置的执行周期是天天早上8点执行,当咱们有天,需求变动,须要天天晚上8点执行,咱们的操做流程为:修改执行周期->新版打包->停服->启动新版服务。整个流程线步骤多,存在不可控因素。编码
那么咱们怎么作到不停服更新咱们的执行周期呢??线程
那么下面咱们模拟将cron表达式存储在MySQL。日志
1)定义cron相关service
// 表达式相关接口 public interface SwitchService { /** * 获取最新 cron 表达式 * * @param taskId 任务ID * @return 最新 cron表达式 */ String getCron(String taskId); /** * 修改 cron 表达式 */ void modify(); }
// 表达式相关接口实现 @Service public class SwitchServiceImpl implements SwitchService { private static String DB_CRON = ""; @Override public String getCron(String taskId) { System.out.println("执行数据库查询 DB_CRON " + LocalDateTime.now()); return DB_CRON; } @Override public void modify() { DB_CRON = "0/20 * * * * *"; System.out.println("修改数据库中 DB_CRON " + LocalDateTime.now()); } }
此处模拟修改以及查询
2)建立具体任务执行
@Component public class DynamicCronTask implements SchedulingConfigurer { // 模拟当前任务ID private String TASK_ID = "5001"; @Autowired private SwitchService switchService; private String SpringDynamicCronTask() { // 默认为 每5秒执行 String cron = "0/5 * * * * ?"; //从数据库得到配置的corn表达式 String dbCron = switchService.getCron(TASK_ID); // 当查询为空时,使用默认的表达式 if (StringUtils.isNotBlank(dbCron)) { return dbCron; } return cron; } @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.addTriggerTask(new Runnable() { @Override public void run() { // 任务逻辑 System.out.println("执行任务逻辑...." + LocalDateTime.now()); } }, new Trigger() { @Override public Date nextExecutionTime(TriggerContext triggerContext) { String s = SpringDynamicCronTask(); // 任务触发,可修改任务的执行周期 CronTrigger trigger = new CronTrigger(s); Date nextExec = trigger.nextExecutionTime(triggerContext); return nextExec; } }); } }
3)启动服务
查看执行日志
执行数据库查询 DB_CRON 2020-06-09T10:33:30.001 执行任务逻辑....2020-06-09T10:33:35.002 执行数据库查询 DB_CRON 2020-06-09T10:33:35.002 执行任务逻辑....2020-06-09T10:33:40.001 执行数据库查询 DB_CRON 2020-06-09T10:33:40.001 修改数据库中 DB_CRON 2020-06-09T10:33:42.085 执行任务逻辑....2020-06-09T10:33:45 执行数据库查询 DB_CRON 2020-06-09T10:33:45 执行任务逻辑....2020-06-09T10:34:00.001 执行数据库查询 DB_CRON 2020-06-09T10:34:00.001 执行任务逻辑....2020-06-09T10:34:20.002 执行数据库查询 DB_CRON 2020-06-09T10:34:20.002
经过日志能够看出,在应用启动时,会首先从数据库中查询配置的执行周期,而后执行定时任务,执行完毕后会再次查询执行周期,下一个执行时间结束后就会按照修改的执行时间执行。
生效时间为下一个执行时间结束后,作不到当即生效!!!