前言:
如果是确定了执行时间或者时间间隔的定时任务,可以用注解@Scheduled来处理(【Spring】【2】使用注解@Scheduled执行定时任务 - 花生喂龙 - 博客园 https://www.cnblogs.com/huashengweilong/p/10934471.html)
但是,有的时候我们的任务是动态的。比如,可以在后台添加任意个数任意时间的推送短信任务,任务没有开始之前,可以更改推送时间。这就需要用到Quartz动态添加、修改和删除定时任务时间了
正文:
1,pom.xml
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency>
2,查询项目中存在哪些定时任务,可以看到定时任务是否符合期望
@CrossOrigin(origins = "*") @RestController public class JobController { @Autowired ControlJob controlJob; //查看定时任务 @RequestMapping(value = "job/list", method = RequestMethod.GET) public List<JobVo> getAllJobs() { return this.controlJob.getAllJobs(); } }
其中的JobVo
//我查看三个参数 private String jobName; //任务名称 private String jobGroup; //任务类型 private String nextFireTime; //下次触发时间
getAllJobs方法
@Service public class ControlJob { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private Scheduler scheduler; public List<JobVo> getAllJobs(){ try { List<JobVo> list = new ArrayList<JobVo>(); for (String groupName : scheduler.getJobGroupNames()) { for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) { JobVo info = new JobVo(); info.setJobName(jobKey.getName()); info.setJobGroup(jobKey.getGroup()); List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey); Date nextFireTime = triggers.get(0).getNextFireTime(); info.setNextFireTime(CalendarUtil.DtoS(nextFireTime)); list.add(info); } } return list; } catch (Exception e) { logger.info("getAllJobs error:" + e); } return null; } }
3,定时查数据库,并根据查询结果决定是否重新设置定时任务(我觉得也可以后台修改任务后,更改定时器。但是由于当时前端接口代码和后台代码不在一块,和后台同事协商后,约定以数据库为桥梁,各自处理各自的部分)
import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobBuilder; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @Service public class TriggerMessage { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); private static String MESSAGE_GROUP_NAME = "MESSAGE"; @Autowired private Scheduler scheduler; @Autowired PushMessageService pushMessageService; @Scheduled(fixedRate = 65000) // 每隔1.5分钟查库,并根据查询结果决定是否重新设置定时任务 public void init(){ //从数据库中获取所有任务。注意PushMessageVo中的corn字段,格式为"ss mm HH dd MM ? yyyy" List<PushMessageVo> jobList = this.pushMessageService.getPushMessageList(); for (PushMessageVo item : jobList) { String jobName = item.getMsgCode(); logger.info("message jobName:"+jobName); try { TriggerKey triggerKey = TriggerKey.triggerKey(jobName, MESSAGE_GROUP_NAME); CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); //判断该定时器是否存在 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(item.getCron()); //表达式调度构建器 if (item.getStatus() == 0){ //状态为0,清理定时器 if (trigger != null) { logger.info("message job clear"); scheduler.pauseTrigger(triggerKey); //停止触发器 scheduler.unscheduleJob(triggerKey); //移除触发器 scheduler.deleteJob(JobKey.jobKey(jobName, MESSAGE_GROUP_NAME)); //删除任务 } } else { if (trigger == null) { //不存在,创建一个 logger.info("message job create"); trigger = TriggerBuilder.newTrigger() .withIdentity(jobName, MESSAGE_GROUP_NAME) .withSchedule(scheduleBuilder) .build(); //按新的cronExpression表达式构建一个新的trigger JobDetail jobDetail = JobBuilder.newJob(PushMessageJob.class).withIdentity(item.getMsgCode(), MESSAGE_GROUP_NAME).build(); jobDetail.getJobDataMap().put("job", item); scheduler.scheduleJob(jobDetail, trigger); } else { //存在,更新 logger.info("message job reset"); trigger = trigger.getTriggerBuilder() .startAt(new Date()) .withIdentity(triggerKey) .withSchedule(scheduleBuilder).build(); JobDataMap jobDataMap = trigger.getJobDataMap(); //重新获取JobDataMap,并且更新参数 jobDataMap.put("job", item); scheduler.rescheduleJob(triggerKey, trigger); //按新的trigger重新设置job执行 } } } catch (Exception e) { logger.info("TriggerMessage error:" + e); } } } }
PushMessageJob(执行的具体内容)
@Configuration @Component @EnableScheduling @DisallowConcurrentExecution public class PushMessageJob implements Job { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); public void execute(JobExecutionContext context) throws JobExecutionException { PushMessageVo info = (PushMessageVo) context.getMergedJobDataMap().get("job"); //获取定时器中信息 String parentCode = info.getMsgCode(); //消息表code logger.info("message code:" + parentCode); //根据parentCode获取通知消息 //获取要推送的成员 //推送 } }
参考博客:
Quartz定时器 官方文档翻译 - 简书
https://www.jianshu.com/p/d1feb7f2821e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
Quartz 2.2 动态添加、修改和删除定时任务 - xlxxcc的专栏 - CSDN博客
https://blog.csdn.net/xlxxcc/article/details/52115995
quartz定时任务cron表达式详解 - 懒惰虫 - 博客园
https://www.cnblogs.com/lazyInsects/p/8075487.html
springboot整合quartz定时器实现定时任务详解 - 上善若水任方圆 - CSDN博客
https://blog.csdn.net/qq_28483283/article/details/80623417
Spring整合Quartz实现动态定时器 - 五指少年 - 博客园
https://www.cnblogs.com/xrab/p/5850186.html
Quartz使用总结 - 路边飞 - 博客园
https://www.cnblogs.com/drift-ice/p/3817269.html
springboot整合Quartz实现动态配置定时任务 - 牛奋lch - CSDN博客
https://blog.csdn.net/liuchuanhong1/article/details/60873295
spring boot整合quartz实现多个定时任务 - 牛奋lch - CSDN博客
https://blog.csdn.net/liuchuanhong1/article/details/78543574