某個項目有需求,某個數據表中有多條數據,每個數據都有自己的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>
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不一致的定時任務,都是正常的在執行。後續有什麼問題會及時更新。