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不一致的定時任務,都是正常的在執行。後續有什麼問題會及時更新。

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