springboot 之quartz动态定时任务实现

某个项目有需求,某个数据表中有多条数据,每个数据都有自己的cron规则,并且能动态的通过接口增加修改停止任务。xxl-job太大了,也用不到这么大的框架,网上查了下,springboot2.0后官方添加了Quartz框架的依赖,相对来说更加轻量级。

参考地址:springboot整合quartz实现定时任务的动态修改,启动,暂停等操作 - 腾讯云开发者社区-腾讯云 (tencent.com)

1、maven引入

      <!--引入quartz定时框架-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
maven

2、创建一个实体类,用来记录一些任务的信息。

@Getter
@Setter
public class QuartzVo {

    /**
     * 任务id
     */
    private String id;

    /**
     * 任务名称
     */
    private String jobName;

    /**
     * 任务状态 启动还是暂停
     */
    private Integer status;

    /**
     * 任务运行时间表达式
     */
    private String cronExpression;

}
任务实体类

3、定时任务动态控制工具类,我这里的执行类包路径写死了,与原文有些区别,为了实现真正的动态定时任务。

public class QuartzUtils {

    /**
     * 创建定时任务 定时任务创建之后默认启动状态
     * @param scheduler   调度器
     * @param quartzBean  定时任务信息类
     * @throws Exception
     */
    public static void createScheduleJob(Scheduler scheduler, QuartzVo quartzBean){
        try {
            //获取到定时任务的执行类  必须是类的绝对路径名称
            //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
            Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName("com.leenleda.data.synchronism.common.task.AutomaticTask");
            // 构建定时任务信息 使用id作为任务唯一值,在执行时可以拿到。
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getId()).withDescription(quartzBean.getJobName()).build();
            // 设置定时任务执行方式
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
            // 构建触发器trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getId()).withSchedule(scheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (ClassNotFoundException e) {
            System.out.println("定时任务类路径出错:请输入类的绝对路径");
        } catch (SchedulerException e) {
            System.out.println("创建定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 根据任务Id暂停定时任务
     * @param scheduler  调度器
     * @param jobId    定时任务名称
     * @throws SchedulerException
     */
    public static void pauseScheduleJob(Scheduler scheduler, String jobId){
        JobKey jobKey = JobKey.jobKey(jobId);
        try {
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("暂停定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 根据任务Id恢复定时任务
     * @param scheduler  调度器
     * @param jobId    定时任务id
     * @throws SchedulerException
     */
    public static void resumeScheduleJob(Scheduler scheduler, String jobId) {
        JobKey jobKey = JobKey.jobKey(jobId);
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("启动定时任务出错:"+e.getMessage());
        }
    }


    /**
     * 根据任务id立即运行一次定时任务
     * @param scheduler     调度器
     * @param jobId       定时任务id
     * @throws SchedulerException
     */
    public static void runOnce(Scheduler scheduler, String jobId){
        JobKey jobKey = JobKey.jobKey(jobId);
        try {
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("运行定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 更新定时任务
     * @param scheduler   调度器
     * @param quartzBean  定时任务信息类
     * @throws SchedulerException
     */
    public static void updateScheduleJob(Scheduler scheduler, QuartzVo quartzBean)  {
        try {
            //获取到对应任务的触发器
            TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getId());
            //设置定时任务执行方式
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
            //重新构建任务的触发器trigger
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            //重置对应的job
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            System.out.println("更新定时任务出错:"+e.getMessage());
        }
    }

    /**
     * 根据定时任务id从调度器当中删除定时任务
     * @param scheduler 调度器
     * @param jobId   定时任务名称
     *
     */
    public static void deleteScheduleJob(Scheduler scheduler, String jobId) {
        JobKey jobKey = JobKey.jobKey(jobId);
        try {
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("删除定时任务出错:"+e.getMessage());
        }
    }
}
工具类

4、创建一个执行类,看到这个应该就知道我的考虑了,这样更加灵活,不用一个任务一个实现类。

public class AutomaticTask extends QuartzJobBean {


    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        // TODO: 2022/8/18   根据key。到数据库取任务类型,取到sql,做对应的业务操作。
        System.out.println(context.getJobDetail().getKey().getName());
    }
}
执行类

5、测试接口

@Controller
@RequestMapping("/quartz/")
public class QuartzController {


    @Autowired
    private Scheduler scheduler;

    @RequestMapping("/createJob")
    @ResponseBody
    public String  createJob(String cron,String id,String name)  {
        try {
            QuartzVo quartzBean=new QuartzVo();
            quartzBean.setJobName(name);
            quartzBean.setCronExpression(cron);
            quartzBean.setId(id);
            QuartzUtils.createScheduleJob(scheduler,quartzBean);
        } catch (Exception e) {
            return "创建失败";
        }
        return "创建成功";
    }

    @RequestMapping("/pauseJob")
    @ResponseBody
    public String  pauseJob()  {
        try {
            QuartzUtils.pauseScheduleJob (scheduler,"1");
        } catch (Exception e) {
            return "暂停失败";
        }
        return "暂停成功";
    }

    @RequestMapping("/runOnce")
    @ResponseBody
    public String  runOnce()  {
        try {
            QuartzUtils.runOnce (scheduler,"1");
        } catch (Exception e) {
            return "运行一次失败";
        }
        return "运行一次成功";
    }

    @RequestMapping("/resume")
    @ResponseBody
    public String  resume()  {
        try {

            QuartzUtils.resumeScheduleJob(scheduler,"1");
        } catch (Exception e) {
            return "启动失败";
        }
        return "启动成功";
    }

    @RequestMapping("/update")
    @ResponseBody
    public String  update(QuartzVo quartzBean)  {
        try {
            //进行测试所以写死
            quartzBean.setJobName("1");
            quartzBean.setCronExpression("3 * * * * ?");
            QuartzUtils.updateScheduleJob(scheduler,quartzBean);
        } catch (Exception e) {
            return "启动失败";
        }
        return "启动成功";
    }
}
测试接口

测试了一下,同时创建多个id不一致的定时任务,都是正常的在执行。后续有什么问题会及时更新。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章