一、本文主要内容

Quartz是一款开源的定时任务调度框架,本文主要记录一下在工作中使用springboot整合quartz实现定时任务调度管理的用例。内容主要有:springboot整合quartz相关配置、实现基于simpleTrigger的定时任务、实现基于cronTrigger的定时任务。

二、代码案例

0、环境准备

  1. @SpringBootApplication
  2. public class QuartzApplication {
  3. public static void main(String[] args){
  4. SpringApplication.run(QuartzApplication.class,args);
  5. }
  6. /**
  7. * 初始注入scheduler
  8. * @return
  9. * @throws SchedulerException
  10. */
  11. @Bean
  12. public Scheduler scheduler() throws SchedulerException {
  13. SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
  14. return schedulerFactoryBean.getScheduler();
  15. }
  16. }

  1. /**
  2. * @Author HanGuangKai
  3. * @Date 2021/7/25 18:55
  4. * @description 定时任务
  5. */
  6. public class MyJob implements Job {
  7. @Override
  8. public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
  9. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
  10. String nowTime = format.format(new Date());
  11. System.out.println("定时任务被触发了"+nowTime);
  12. }
  13. }

1、开启一个任务

  1. /**
  2. * @Author HanGuangKai
  3. * @Date 2021/7/25 18:58
  4. * @description quartz配置类
  5. */
  6. @Configuration
  7. public class QuartzConfig {
  8. @Resource
  9. private Scheduler scheduler;
  10. /**
  11. * 01-开启任务
  12. */
  13. public void startJob() {
  14. openJob(scheduler);
  15. // 启动任务
  16. try {
  17. scheduler.start();
  18. } catch (SchedulerException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. /**
  23. * 开启一个任务
  24. * @param scheduler
  25. */
  26. private void openJob(Scheduler scheduler) {
  27. // 1.创建一个JobDetail
  28. JobDetail build = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build();
  29. // 2.触发器表达式对象
  30. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/4 * * * * ?");
  31. // 3.准备一个出触发器对象
  32. CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggergroup1")
  33. .withSchedule(cronScheduleBuilder).build();
  34. // 4.开始调度
  35. try {
  36. scheduler.scheduleJob(build, cronTrigger);
  37. } catch (SchedulerException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. }
  1. @RestController
  2. @RequestMapping(value = "/quartz")
  3. public class QuartzController {
  4. // 任务调度器
  5. @Autowired
  6. private QuartzConfig quartzConfig;
  7. /**
  8. * 开启一个定时任务
  9. */
  10. @RequestMapping(value = "open-job")
  11. public String openJob() {
  12. quartzConfig.startJob();
  13. return "定时任务开启成功!";
  14. }
  15. }

2、暂停一个任务

  1. @Configuration
  2. public class QuartzConfig {
  3. @Resource
  4. private Scheduler scheduler;
  5. /**
  6. * 暂停一个任务
  7. * @param name 任务名
  8. * @param group 任务组名
  9. */
  10. public void pauseJob(String name,String group) throws SchedulerException {
  11. // 任务的标识类
  12. JobKey jobKey = new JobKey(name, group);
  13. // 获取此任务
  14. JobDetail jobDetail = scheduler.getJobDetail(jobKey);
  15. if (jobDetail != null) {
  16. // 暂停此任务
  17. scheduler.pauseJob(jobKey);
  18. } else {
  19. System.out.println("无此定时任务!");
  20. }
  21. }
  22. }
  1. public class QuartzController {
  2. // 任务调度器
  3. @Autowired
  4. private QuartzConfig quartzConfig;
  5. @RequestMapping(value = "pause-job")
  6. public String pauseJob(@RequestParam("name") String name, @RequestParam("group") String group) {
  7. try {
  8. quartzConfig.pauseJob(name, group);
  9. } catch (SchedulerException e) {
  10. e.printStackTrace();
  11. return "任务暂停异常!";
  12. }
  13. return "任务暂停成功!";
  14. }
  15. }

3、打印任务的基本信息

  1. /**
  2. * @Author HanGuangKai
  3. * @Date 2021/7/25 19:49
  4. * @description 任务对象
  5. */
  6. @Data
  7. @AllArgsConstructor
  8. @NoArgsConstructor
  9. public class TaskInfo {
  10. private String jobName;
  11. private String jobGroup;
  12. private String jobDescription;
  13. private String status;
  14. private String cronExpression;
  15. private String cronDescription;
  16. }
  1. /**
  2. * 查看所有的任务信息
  3. * @return
  4. */
  5. public List<TaskInfo> getAllJobsInfo() throws SchedulerException {
  6. ArrayList<TaskInfo> taskInfos = new ArrayList<>();
  7. // 所有任务组
  8. List<String> jobGroupNames = scheduler.getJobGroupNames();
  9. for (String jobGroupName : jobGroupNames) {
  10. Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(jobGroupName));
  11. for (JobKey jobKey : jobKeys) {
  12. List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
  13. for (Trigger trigger : triggers) {
  14. Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
  15. JobDetail jobDetail = scheduler.getJobDetail(jobKey);
  16. String cronException = ""; // cron表达式
  17. String cronDescription = ""; // 描述信息
  18. if (trigger instanceof CronTrigger) {
  19. CronTrigger cronTrigger = (CronTrigger)trigger;
  20. // cron表达式
  21. cronException = cronTrigger.getCronExpression();
  22. cronDescription = cronTrigger.getDescription();
  23. }
  24. TaskInfo taskInfo = new TaskInfo();
  25. taskInfo.setJobName(jobKey.getName());
  26. taskInfo.setJobGroup(jobKey.getGroup());
  27. taskInfo.setJobDescription(jobDetail.getDescription());
  28. taskInfo.setStatus(triggerState.name());
  29. taskInfo.setCronExpression(cronException);
  30. taskInfo.setJobDescription(cronDescription);
  31. taskInfos.add(taskInfo);
  32. }
  33. }
  34. }
  1. @RequestMapping(value = "get-all-job")
  2. public List<TaskInfo> getAllTasks() {
  3. List<TaskInfo> allJobsInfo = null;
  4. try {
  5. allJobsInfo = quartzConfig.getAllJobsInfo();
  6. } catch (SchedulerException e) {
  7. e.printStackTrace();
  8. return null;
  9. }
  10. return allJobsInfo;
  11. }

4、关于暂停和恢复任务

  1. /**
  2. * 恢复某个定时任务的执行
  3. * @param name
  4. * @param group
  5. */
  6. public void resumeJob(String name,String group) throws SchedulerException {
  7. JobKey jobKey = new JobKey(name, group);
  8. JobDetail jobDetail = scheduler.getJobDetail(jobKey);
  9. if (jobDetail != null) {
  10. scheduler.resumeJob(jobKey);
  11. } else {
  12. System.out.println("要恢复的任务不存在");
  13. }
  14. }
  1. @RequestMapping(value = "resume-job")
  2. public String resumeJob(@RequestParam("name") String name, @RequestParam("group") String group) {
  3. try {
  4. quartzConfig.resumeJob(name, group);
  5. } catch (SchedulerException e) {
  6. e.printStackTrace();
  7. return "任务恢复异常!";
  8. }
  9. return "任务恢复成功!";
  10. }

当暂停一个定时任务后,再将其恢复,会发现控制台输出很多遍相同内容:(即把之前暂停应该打印的内容,在恢复后重新打印了一遍)

  1. 定时任务被触发了2021-07-25 08:23:28
  2. 定时任务被触发了2021-07-25 08:23:42
  3. 定时任务被触发了2021-07-25 08:23:42
  4. 定时任务被触发了2021-07-25 08:23:42
  5. 定时任务被触发了2021-07-25 08:23:44

5、删除任务

  1. /**
  2. * 删除某个定时任务
  3. * @param name
  4. * @param group
  5. */
  6. public void deleteJob(String name,String group) throws SchedulerException {
  7. JobKey jobKey = new JobKey(name, group);
  8. JobDetail jobDetail = scheduler.getJobDetail(jobKey);
  9. if (jobDetail != null) {
  10. scheduler.deleteJob(jobKey);
  11. } else {
  12. System.out.println("要删除的任务不存在");
  13. }
  14. }
  1. @RequestMapping(value = "delete-job")
  2. public String deleteJob(@RequestParam("name") String name, @RequestParam("group") String group) {
  3. try {
  4. quartzConfig.deleteJob(name, group);
  5. } catch (SchedulerException e) {
  6. e.printStackTrace();
  7. return "任务删除异常!";
  8. }
  9. return "任务删除成功!";
  10. }

6、动态修改一个定时任务

  1. /**
  2. * 动态修改一个定时任务的cron表达式(即触发规则)
  3. */
  4. public boolean modifyJob(String name,String group,String newTime) throws SchedulerException {
  5. Date date = null;
  6. TriggerKey triggerKey = new TriggerKey(name, group);
  7. Trigger trigger = scheduler.getTrigger(triggerKey);
  8. CronTrigger cronTrigger = null;
  9. if (trigger instanceof CronTrigger) {
  10. cronTrigger = (CronTrigger) trigger;
  11. // 获取到表达式
  12. String cronExpression = cronTrigger.getCronExpression();
  13. if (cronExpression.equalsIgnoreCase(newTime)) {
  14. System.out.println("需要修改原来的表达式:"+cronExpression+"为"+newTime);
  15. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(newTime);
  16. // 新的cronTrigger1
  17. CronTrigger cronTrigger1 = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(cronScheduleBuilder).build();
  18. date = scheduler.rescheduleJob(triggerKey, cronTrigger1);
  19. } else {
  20. System.out.println("二者一样,不用修改");
  21. }
  22. }
  23. if (date != null) {
  24. return true;
  25. } else {
  26. return false;
  27. }
  1. @RequestMapping("modify-job")
  2. public boolean modifyJob(@RequestParam("name") String name, @RequestParam("group") String group,@RequestParam("cron") String cron) {
  3. boolean b = false;
  4. try {
  5. b = quartzConfig.modifyJob(name, group, cron);
  6. } catch (SchedulerException e) {
  7. e.printStackTrace();
  8. return b;
  9. }
  10. return b;
  11. }

7、web项目开启时便开启定时任务

  1. package com.hgk.quartz.listener;
  2. import com.hgk.quartz.config.QuartzConfig;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.context.ApplicationListener;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.context.event.ContextRefreshedEvent;
  7. /**
  8. * @Author HanGuangKai
  9. * @Date 2021/7/26 20:07
  10. * @description 自定义一个监听器监听web启动
  11. */
  12. @Configuration
  13. public class QuartzListener implements ApplicationListener<ContextRefreshedEvent> {
  14. @Autowired
  15. private QuartzConfig quartzConfig;
  16. @Override
  17. public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
  18. quartzConfig.startJob();
  19. System.out.println("web项目启动了!");
  20. }
  21. }

8、如何在JOB任务中获取Spring容器中的对象-为了调用方法

  1. /**
  2. * 开启一个任务
  3. * @param scheduler
  4. */
  5. private void openJob(Scheduler scheduler) {
  6. // 将spring上下文对象放到容器中
  7. JobDataMap map = new JobDataMap();
  8. map.put("applicationContext",applicationContext);
  9. // 然后创建对象的时候传过去
  10. // 1.创建一个JobDetail
  11. JobDetail build = JobBuilder.newJob(MyJob.class).usingJobData(map)
  12. .withIdentity("job1", "group1").build();
  13. // 2.触发器表达式对象
  14. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/4 * * * * ?");
  15. // 3.准备一个出触发器对象
  16. CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggergroup1")
  17. .withSchedule(cronScheduleBuilder).build();
  18. // 4.开始调度
  19. try {
  20. scheduler.scheduleJob(build, cronTrigger);
  21. } catch (SchedulerException e) {
  22. e.printStackTrace();
  23. }
  24. }
  1. public class MyJob implements Job {
  2. @Override
  3. public void execute(JobExecutionContext context) throws JobExecutionException {
  4. ApplicationContext applicationContext1 = (ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");
  5. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
  6. String nowTime = format.format(new Date());
  7. System.out.println("定时任务被触发了"+nowTime);
  8. // 现在就可以调用业务逻辑层方法了(从spring容器中获取对象)
  9. OrderService orderService = applicationContext1.getBean(OrderService.class);
  10. orderService.sayHi();
  11. }
  12. }

9、关于quartz的暂停补偿问题

  1. /**
  2. * 开启一个任务
  3. * @param scheduler
  4. */
  5. private void openJob(Scheduler scheduler) {
  6. // 将spring上下文对象放到容器中
  7. JobDataMap map = new JobDataMap();
  8. map.put("applicationContext",applicationContext);
  9. // 然后创建对象的时候传过去
  10. // 1.创建一个JobDetail
  11. JobDetail build = JobBuilder.newJob(MyJob.class).usingJobData(map)
  12. .withIdentity("job1", "group1").build();
  13. // 2.触发器表达式对象
  14. /**
  15. * withMisfireHandlingInstructionDoNothing():不触发立即执行,一个任务恢复执行,以前错过的定时任务不补偿,继续执行下一个周期
  16. * withMisfireHandlingInstructionFireAndProceed():以当前时间先触发一次,以后继续按照cron执行
  17. * withMisfireHandlingInstructionIgnoreMisfires():举例:如果九点暂停定时任务,十点十五恢复定时任务,错误的九点十点的定时任务补偿,以后正常执行
  18. */
  19. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/4 * * * * ?").withMisfireHandlingInstructionDoNothing();
  20. // 3.准备一个出触发器对象
  21. CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggergroup1")
  22. .withSchedule(cronScheduleBuilder).build();
  23. // 4.开始调度
  24. try {
  25. scheduler.scheduleJob(build, cronTrigger);
  26. } catch (SchedulerException e) {
  27. e.printStackTrace();
  28. }
  29. }

注意:还要写配置文件withMisfireHandlingInstructionDoNothing才能生效。