Springboot中使用定时器

  • 前言
  • 需求执行策略
  • 代码部分
  • 后话


前言

有个需求是不重启服务器的前提下动态修改cron表达式达到修改下次执行时间的目的。一开始参照找的教程去修改cron表达式,但总会出现一些问题,比如修改完执行时间但下一次的执行时间还是按照默认设置的时间去走,这是因为启动服务器后未到第一次执行任务就修改时间导致修改不生效 等问题,奇奇怪怪,于是后面就放弃了这种动态修改的策略

需求执行策略

  1. 服务器启动执行启动定时器步骤
  2. 查询数据库查看是否有cron表达式,有则使用此表达式并赋值给类中的cron属性,无则使用类中定义的默认表达式,启动服务器
  3. 页面修改执行时间,在后台代码中转换为cron表达式,存储至数据库
  4. 修改类中定义的cron表达式,关闭定时器,启动定时器

代码部分

  1. 定时器类
@Service
@Component
public class SchedulerService{
    private String cron = "0 30 08 * * ? ";
    ThreadPoolTaskScheduler threadPoolTaskScheduler;

    private ScheduledFuture<?> future;

/**
	poolsize属性,如果项目中有多个定时器,需要设置多个
*/
    @Bean
    public TaskScheduler poolScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("threadPoolTaskScheduler");
        scheduler.setPoolSize(10);
        scheduler.initialize();
        threadPoolTaskScheduler = scheduler;
        return scheduler;
    }

    private Integer getDay(String now, String target){
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");

        try{
            Long c = sf.parse(now).getTime()-sf.parse(target).getTime();
            long d = c/1000/60/60/24;
            return new Long(d).intValue();
        }catch (Exception e){
            return -1;
        }
    }

    public void setCron(String cron) {
        this.cron = cron;
        System.out.println(this.cron);
    }

    public void startCron() {

        future = threadPoolTaskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                //执行业务逻辑,代码省略
        }, new CronTrigger(cron));
        System.out.println("DynamicTask.startCron()");
    }

    public String stopCron() {
        if (future != null) {
            future.cancel(true);
        }
        System.out.println("DynamicTask.stopCron()");
        return "stopCron";
    }
}
  1. 服务器启动时启动定时器
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {

    @Autowired
    SchedulerService schedulerService;
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        //重写此方法,即可实现在服务器启动时执行部分代码
        //获取数据库中的cron表达式,设置并启动定时器
        schedulerService.setCron(cron);
        schedulerService.startCron();
    }
}
  1. 修改执行时间部分代码
public void change_cron(){
	//业务部分,代码省略
	//修改定时器执行时间,设置cron表达式, 先停止定时器,再重启
	schedulerService.setCron(cronStr);
    schedulerService.stopCron();
    schedulerService.startCron();
}

后话

  1. 这样就可以实现动态修改定时器的执行时间的需求
  2. 这种处理方式实际是一种迂回的实现方式,从项目优化的角度看,肯定没有单纯的修改执行时间的方式好。
  3. 这只是个项目小笔记,记录使用方式,不探究个中原理