一、本文主要内容
Quartz是一款开源的定时任务调度框架,本文主要记录一下在工作中使用springboot整合quartz实现定时任务调度管理的用例。内容主要有:springboot整合quartz相关配置、实现基于simpleTrigger的定时任务、实现基于cronTrigger的定时任务。
二、代码案例
0、环境准备
@SpringBootApplicationpublic class QuartzApplication {public static void main(String[] args){SpringApplication.run(QuartzApplication.class,args);}/*** 初始注入scheduler* @return* @throws SchedulerException*/@Beanpublic Scheduler scheduler() throws SchedulerException {SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();return schedulerFactoryBean.getScheduler();}}
/*** @Author HanGuangKai* @Date 2021/7/25 18:55* @description 定时任务*/public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");String nowTime = format.format(new Date());System.out.println("定时任务被触发了"+nowTime);}}
1、开启一个任务
/*** @Author HanGuangKai* @Date 2021/7/25 18:58* @description quartz配置类*/@Configurationpublic class QuartzConfig {@Resourceprivate Scheduler scheduler;/*** 01-开启任务*/public void startJob() {openJob(scheduler);// 启动任务try {scheduler.start();} catch (SchedulerException e) {e.printStackTrace();}}/*** 开启一个任务* @param scheduler*/private void openJob(Scheduler scheduler) {// 1.创建一个JobDetailJobDetail build = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build();// 2.触发器表达式对象CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/4 * * * * ?");// 3.准备一个出触发器对象CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggergroup1").withSchedule(cronScheduleBuilder).build();// 4.开始调度try {scheduler.scheduleJob(build, cronTrigger);} catch (SchedulerException e) {e.printStackTrace();}}}
@RestController@RequestMapping(value = "/quartz")public class QuartzController {// 任务调度器@Autowiredprivate QuartzConfig quartzConfig;/*** 开启一个定时任务*/@RequestMapping(value = "open-job")public String openJob() {quartzConfig.startJob();return "定时任务开启成功!";}}
2、暂停一个任务
@Configurationpublic class QuartzConfig {@Resourceprivate Scheduler scheduler;/*** 暂停一个任务* @param name 任务名* @param group 任务组名*/public void pauseJob(String name,String group) throws SchedulerException {// 任务的标识类JobKey jobKey = new JobKey(name, group);// 获取此任务JobDetail jobDetail = scheduler.getJobDetail(jobKey);if (jobDetail != null) {// 暂停此任务scheduler.pauseJob(jobKey);} else {System.out.println("无此定时任务!");}}}
public class QuartzController {// 任务调度器@Autowiredprivate QuartzConfig quartzConfig;@RequestMapping(value = "pause-job")public String pauseJob(@RequestParam("name") String name, @RequestParam("group") String group) {try {quartzConfig.pauseJob(name, group);} catch (SchedulerException e) {e.printStackTrace();return "任务暂停异常!";}return "任务暂停成功!";}}
3、打印任务的基本信息
/*** @Author HanGuangKai* @Date 2021/7/25 19:49* @description 任务对象*/@Data@AllArgsConstructor@NoArgsConstructorpublic class TaskInfo {private String jobName;private String jobGroup;private String jobDescription;private String status;private String cronExpression;private String cronDescription;}
/*** 查看所有的任务信息* @return*/public List<TaskInfo> getAllJobsInfo() throws SchedulerException {ArrayList<TaskInfo> taskInfos = new ArrayList<>();// 所有任务组List<String> jobGroupNames = scheduler.getJobGroupNames();for (String jobGroupName : jobGroupNames) {Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(jobGroupName));for (JobKey jobKey : jobKeys) {List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);for (Trigger trigger : triggers) {Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());JobDetail jobDetail = scheduler.getJobDetail(jobKey);String cronException = ""; // cron表达式String cronDescription = ""; // 描述信息if (trigger instanceof CronTrigger) {CronTrigger cronTrigger = (CronTrigger)trigger;// cron表达式cronException = cronTrigger.getCronExpression();cronDescription = cronTrigger.getDescription();}TaskInfo taskInfo = new TaskInfo();taskInfo.setJobName(jobKey.getName());taskInfo.setJobGroup(jobKey.getGroup());taskInfo.setJobDescription(jobDetail.getDescription());taskInfo.setStatus(triggerState.name());taskInfo.setCronExpression(cronException);taskInfo.setJobDescription(cronDescription);taskInfos.add(taskInfo);}}}
@RequestMapping(value = "get-all-job")public List<TaskInfo> getAllTasks() {List<TaskInfo> allJobsInfo = null;try {allJobsInfo = quartzConfig.getAllJobsInfo();} catch (SchedulerException e) {e.printStackTrace();return null;}return allJobsInfo;}
4、关于暂停和恢复任务
/*** 恢复某个定时任务的执行* @param name* @param group*/public void resumeJob(String name,String group) throws SchedulerException {JobKey jobKey = new JobKey(name, group);JobDetail jobDetail = scheduler.getJobDetail(jobKey);if (jobDetail != null) {scheduler.resumeJob(jobKey);} else {System.out.println("要恢复的任务不存在");}}
@RequestMapping(value = "resume-job")public String resumeJob(@RequestParam("name") String name, @RequestParam("group") String group) {try {quartzConfig.resumeJob(name, group);} catch (SchedulerException e) {e.printStackTrace();return "任务恢复异常!";}return "任务恢复成功!";}
当暂停一个定时任务后,再将其恢复,会发现控制台输出很多遍相同内容:(即把之前暂停应该打印的内容,在恢复后重新打印了一遍)
定时任务被触发了2021-07-25 08:23:28定时任务被触发了2021-07-25 08:23:42定时任务被触发了2021-07-25 08:23:42定时任务被触发了2021-07-25 08:23:42定时任务被触发了2021-07-25 08:23:44
5、删除任务
/*** 删除某个定时任务* @param name* @param group*/public void deleteJob(String name,String group) throws SchedulerException {JobKey jobKey = new JobKey(name, group);JobDetail jobDetail = scheduler.getJobDetail(jobKey);if (jobDetail != null) {scheduler.deleteJob(jobKey);} else {System.out.println("要删除的任务不存在");}}
@RequestMapping(value = "delete-job")public String deleteJob(@RequestParam("name") String name, @RequestParam("group") String group) {try {quartzConfig.deleteJob(name, group);} catch (SchedulerException e) {e.printStackTrace();return "任务删除异常!";}return "任务删除成功!";}
6、动态修改一个定时任务
/*** 动态修改一个定时任务的cron表达式(即触发规则)*/public boolean modifyJob(String name,String group,String newTime) throws SchedulerException {Date date = null;TriggerKey triggerKey = new TriggerKey(name, group);Trigger trigger = scheduler.getTrigger(triggerKey);CronTrigger cronTrigger = null;if (trigger instanceof CronTrigger) {cronTrigger = (CronTrigger) trigger;// 获取到表达式String cronExpression = cronTrigger.getCronExpression();if (cronExpression.equalsIgnoreCase(newTime)) {System.out.println("需要修改原来的表达式:"+cronExpression+"为"+newTime);CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(newTime);// 新的cronTrigger1CronTrigger cronTrigger1 = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(cronScheduleBuilder).build();date = scheduler.rescheduleJob(triggerKey, cronTrigger1);} else {System.out.println("二者一样,不用修改");}}if (date != null) {return true;} else {return false;}
@RequestMapping("modify-job")public boolean modifyJob(@RequestParam("name") String name, @RequestParam("group") String group,@RequestParam("cron") String cron) {boolean b = false;try {b = quartzConfig.modifyJob(name, group, cron);} catch (SchedulerException e) {e.printStackTrace();return b;}return b;}
7、web项目开启时便开启定时任务
package com.hgk.quartz.listener;import com.hgk.quartz.config.QuartzConfig;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationListener;import org.springframework.context.annotation.Configuration;import org.springframework.context.event.ContextRefreshedEvent;/*** @Author HanGuangKai* @Date 2021/7/26 20:07* @description 自定义一个监听器监听web启动*/@Configurationpublic class QuartzListener implements ApplicationListener<ContextRefreshedEvent> {@Autowiredprivate QuartzConfig quartzConfig;@Overridepublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {quartzConfig.startJob();System.out.println("web项目启动了!");}}
8、如何在JOB任务中获取Spring容器中的对象-为了调用方法
/*** 开启一个任务* @param scheduler*/private void openJob(Scheduler scheduler) {// 将spring上下文对象放到容器中JobDataMap map = new JobDataMap();map.put("applicationContext",applicationContext);// 然后创建对象的时候传过去// 1.创建一个JobDetailJobDetail build = JobBuilder.newJob(MyJob.class).usingJobData(map).withIdentity("job1", "group1").build();// 2.触发器表达式对象CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/4 * * * * ?");// 3.准备一个出触发器对象CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggergroup1").withSchedule(cronScheduleBuilder).build();// 4.开始调度try {scheduler.scheduleJob(build, cronTrigger);} catch (SchedulerException e) {e.printStackTrace();}}
public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {ApplicationContext applicationContext1 = (ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");String nowTime = format.format(new Date());System.out.println("定时任务被触发了"+nowTime);// 现在就可以调用业务逻辑层方法了(从spring容器中获取对象)OrderService orderService = applicationContext1.getBean(OrderService.class);orderService.sayHi();}}
9、关于quartz的暂停补偿问题
/*** 开启一个任务* @param scheduler*/private void openJob(Scheduler scheduler) {// 将spring上下文对象放到容器中JobDataMap map = new JobDataMap();map.put("applicationContext",applicationContext);// 然后创建对象的时候传过去// 1.创建一个JobDetailJobDetail build = JobBuilder.newJob(MyJob.class).usingJobData(map).withIdentity("job1", "group1").build();// 2.触发器表达式对象/*** withMisfireHandlingInstructionDoNothing():不触发立即执行,一个任务恢复执行,以前错过的定时任务不补偿,继续执行下一个周期* withMisfireHandlingInstructionFireAndProceed():以当前时间先触发一次,以后继续按照cron执行* withMisfireHandlingInstructionIgnoreMisfires():举例:如果九点暂停定时任务,十点十五恢复定时任务,错误的九点十点的定时任务补偿,以后正常执行*/CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/4 * * * * ?").withMisfireHandlingInstructionDoNothing();// 3.准备一个出触发器对象CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggergroup1").withSchedule(cronScheduleBuilder).build();// 4.开始调度try {scheduler.scheduleJob(build, cronTrigger);} catch (SchedulerException e) {e.printStackTrace();}}
注意:还要写配置文件withMisfireHandlingInstructionDoNothing才能生效。
