admin管理员组

文章数量:1530359

上一篇文章介绍了基于SchedulingConfigurer实现定时任务实时配置cron表达式和开关,存在一个问题:修改完cron表达式后不能立刻生效,需要等到下一次定时任务执行后才可以生效。本文更换实现思路,从ThreadPoolTaskScheduler类入手,解决这个问题。

核心类

@Slf4j
@Component
public class MyScheduleComponent {

    @Resource
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Resource
    private SysConfigDao sysConfigDao;
    @Autowired
    private TaskService taskService;

    private ScheduledFuture<?> future;

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        return new ThreadPoolTaskScheduler();
    }

    /**
     * 初始化定时任务,确保项目启动的时候会根据配置自动执行
     */
    @PostConstruct
    public void initScheduler(){
        // 先判断数据库保存的开关状态,如果开关为off则不执行定时任务
        String status = sysConfigDao.getValueByKey(ScheduleConstant.STATUS_KEY);
        if(StringUtils.isEmpty(status) || !ScheduleConstant.DEFAULT_STATUS.equals(status)){
            return;
        }

        String cron = sysConfigDao.getValueByKey(ScheduleConstant.CRON_KEY);
        log.info("【定时任务】cron配置:{}", cron);
        if(StringUtils.isEmpty(cron)){
            log.info("【定时任务】缺少cron配置,将使用默认配置,每10秒执行一次");
            cron = ScheduleConstant.DEFAULT_CRON;
        }
        startCron(cron);
    }

    /**
     * 开启定时任务
     * @param cron
     */
    public void startCron(String cron){
        // 先关闭
        stopCron();
        future = threadPoolTaskScheduler.schedule(()->{
            log.info("【定时任务】任务开始执行");
            String status = sysConfigDao.getValueByKey(ScheduleConstant.STATUS_KEY);
            log.info("【定时任务】开关配置:{}", status);
            if(StringUtils.isEmpty(status)){
                log.info("【定时任务】缺少开关配置,将使用默认配置:on");
                status = ScheduleConstant.DEFAULT_STATUS;
            }
            if("on".equals(status)){
                // 执行业务
                taskService.doTask();
            }
        }, new CronTrigger(cron));
    }

    /**
     * 关闭定时任务
     */
    public void stopCron(){
        log.info("【定时任务】定时任务关闭");
        if(future != null){
            future.cancel(true);
        }
    }

    /**
     * 修改cron表达式,一经修改立即生效
     * @param cron
     */
    public void changeCron(String cron){
        log.info("【定时任务】修改定时任务,cron = {}", cron);
        startCron(cron);
    }
}

控制器代码

@RestController
public class ScheduleController {

    @Resource
    private SysConfigDao sysConfigDao;
    @Resource
    private MyScheduleComponent mySchedule;

    /**
     * 获取配置信息
     * @return
     */
    @GetMapping("config")
    public Map<String, String> config(){
        String cron = sysConfigDao.getValueByKey(ScheduleConstant.CRON_KEY);
        String status = sysConfigDao.getValueByKey(ScheduleConstant.STATUS_KEY);
        Map<String, String> result = new HashMap<>();
        result.put("cron", cron);
        result.put("status", status);
        return result;
    }

    /**
     * 修改表达式
     * @param cron
     * @return
     */
    @PutMapping("cron")
    public String cron(@RequestParam(value = "cron", required = true) String cron){
        // TODO cron表达式做格式校验
        // 先修改数据库
        sysConfigDao.updateValueByKey(ScheduleConstant.CRON_KEY, cron);
        // 再修改cron
        mySchedule.changeCron(cron);
        return "success";
    }

    /**
     * 修改开关状态
     * @param status
     * @return
     */
    @PutMapping("status")
    public String status(@RequestParam(value = "status", required = true)String status){
        // TODO status做格式校验
        sysConfigDao.updateValueByKey(ScheduleConstant.STATUS_KEY, status);
        mySchedule.stopCron();
        return "success";
    }

}

测试结果

项目启动时定时任务已经生效:

用postman测试修改cron表达式,从10秒执行一次修改为30秒执行一次:

日志输出如下:

从日志可以看到,定时任务立刻生效了。

用postman测试关闭定时任务:

日志输出如下,定时任务成功关闭。
最后附上代码:
定时任务实时配置cron表达式和开关(升级版)示例代码

本文标签: 表达式升级版实时schedulecron