功能点Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。该文章不过多介绍Quartz的概念,主要做一个封装的记录。
- 添加CRON、固定间隔定时
- 修改定时的触发器
- 修改定时参数
- 暂停定时
- 启动暂停的定时
- 获取所有定时
- 启动所有定时
- 停止定时
创建一个简单的SpringBoot项目,pom如下:
1. 定时类型4.0.0 org.springframework.boot spring-boot-starter-parent2.6.1 org.demo quartz0.0.1-SNAPSHOT quartz Demo project for Spring Boot 11 org.springframework.boot spring-boot-starterorg.springframework.boot spring-boot-starter-testtest org.springframework.boot spring-boot-starter-quartzorg.projectlombok lombokorg.springframework.boot spring-boot-maven-plugin
Quartz可以通过org.quartz.Trigger.class去拓展定时类型的,目前需求需要支持CRON和固定间隔两种定时类型,后期需要支持跳过节假日、周一~周五、周末等需求,所以需要让定时类型支持拓展。
1.1定时类型package org.demo.quartz.mode; public enum TriggerType { CRON("标准CRON支持"), INTERVAL_MILLISECOND("固定间隔毫秒"), INTERVAL_SECOND("固定间隔秒"), INTERVAL_MINUTE("固定间隔分钟"), INTERVAL_HOUR("固定间隔小时"), WEEKDAYS("工作日,跳过节假日"), HOLIDAY("节假日") ; private String describe; TriggerType(String describe) { this.describe = describe; } }1.2 构建定时任务的抽象类
我们需要构建不同的定时类型,不同的定时类型需要的参数也是不同的,因此我们需要抽象出定时的公用参数,将不同的参数多态实现。
package org.demo.quartz.mode; import lombok.Getter; import lombok.Setter; import org.demo.quartz.task.QuartzTaskJob; import java.util.Map; @Getter @Setter public class TimingModel { private Class extends QuartzTaskJob> taskClass; private String taskName; private String groupName; private String description; private TriggerType type; private Map1.3 用以构建CRON定时任务param; private String taskStatus; public TimingModel(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Map param) { this.taskClass = taskClass; this.taskName = taskName; this.groupName = groupName; this.description = description; this.type = type; this.param = param; } public TimingModel(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type) { this.taskClass = taskClass; this.taskName = taskName; this.groupName = groupName; this.description = description; this.type = type; } }
package org.demo.quartz.mode; import lombok.Getter; import lombok.Setter; import org.demo.quartz.task.QuartzTaskJob; import java.util.Map; @Getter @Setter public class CronTimingModel extends TimingModel{ private String cronexpression; public CronTimingModel(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, Map1.4 用以构建固定间隔定时任务param,String cronexpression) { super(taskClass, taskName, groupName, description, TriggerType.CRON, param); this.cronexpression = cronexpression; } public CronTimingModel(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description,String cronexpression) { super(taskClass, taskName, groupName, description, TriggerType.CRON); this.cronexpression = cronexpression; } }
package org.demo.quartz.mode; import lombok.Getter; import lombok.Setter; import org.demo.quartz.exception.TimingException; import org.demo.quartz.task.QuartzTaskJob; import java.util.Map; @Getter @Setter public class IntervalTimingMode extends TimingModel { private Long interval; private Integer repeatCount; public IntervalTimingMode(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Map2.抽象任务类param, Long interval,Integer repeatCount) { super(taskClass, taskName, groupName, description, type, param); if (type != TriggerType.INTERVAL_MILLISECOND){ if (interval<(-2^32)||interval>(2^31)){ throw new TimingException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)"); } } this.interval = interval; this.repeatCount = repeatCount; } public IntervalTimingMode(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Long interval,Integer repeatCount) { super(taskClass, taskName, groupName, description, type); if (type != TriggerType.INTERVAL_MILLISECOND){ if (interval<(-2^32)||interval>(2^31)){ throw new TimingException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)"); } } this.interval = interval; this.repeatCount = repeatCount; } }
package org.demo.quartz.task; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public interface QuartzTaskJob extends Job { @Override void execute(JobExecutionContext context) throws JobExecutionException; }2.1 实现一个测试任务
package org.demo.quartz.task; import lombok.extern.slf4j.Slf4j; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.SimpleTrigger; import org.springframework.stereotype.Component; @Component @Slf4j public class TestQuartz implements QuartzTaskJob { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 获取参数 JobDataMap jobDataMap = context.getTrigger().getJobDataMap(); // 获取任务名 String name = context.getJobDetail().getJobBuilder().build().getKey().getName(); // 获取任务分组 String group = context.getJobDetail().getJobBuilder().build().getKey().getGroup(); // 获取任务描述 String description = context.getJobDetail().getDescription(); if (context.getTrigger() instanceof SimpleTrigger){ // 运行次数 System.out.println(((SimpleTrigger)context.getTrigger()).getTimesTriggered()); } log.info("----------------------" + "n任务组:{}n任务名:{}n任务描述:{}n获取参数paramKey:{}n" + "----------------------" ,name,group,description,jobDataMap.getString("paramKey")); try { // QuartzJobManager.getInstance().jobdelete(this.getClass().getSimpleName(),"ah");//执行完此任务就删除自己 } catch (Exception e) { e.printStackTrace(); } } }3. 构建触发器的不同实现 3.1 抽象触发器实现
package org.demo.quartz.trigger; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.mode.TimingModel; import org.quartz.Trigger; public interface ITriggerFactory { public boolean check(TriggerType triggerType); public Trigger build(TimingModel timingModel); }3.2 CRON触发器
package org.demo.quartz.trigger.factory; import org.demo.quartz.exception.TimingException; import org.demo.quartz.mode.CronTimingModel; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.mode.TimingModel; import org.demo.quartz.trigger.ITriggerFactory; import org.quartz.CronScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.springframework.stereotype.Component; @Component public class CronTrigger implements ITriggerFactory { @Override public boolean check(TriggerType triggerType) { return triggerType==TriggerType.CRON; } @Override public Trigger build(TimingModel timingModel) { if (!(timingModel instanceof CronTimingModel)){ throw new TimingException("构建类型为CRON定时必须传入CronTimingModel.class的实现类"); } //按新的cronexpression表达式构建一个新的trigger CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(((CronTimingModel) timingModel).getCronexpression()); return TriggerBuilder.newTrigger().withIdentity(timingModel.getTaskName(), timingModel.getTaskName()) .withSchedule(scheduleBuilder).build(); } }3.3 固定间隔触发器
package org.demo.quartz.trigger.factory; import org.demo.quartz.exception.TimingException; import org.demo.quartz.mode.IntervalTimingMode; import org.demo.quartz.mode.TimingModel; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.trigger.ITriggerFactory; import org.quartz.SimpleScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.springframework.stereotype.Component; @Component public class IntervalTrigger implements ITriggerFactory { @Override public boolean check(TriggerType triggerType) { return triggerType == TriggerType.INTERVAL_MINUTE || triggerType == TriggerType.INTERVAL_SECOND || triggerType == TriggerType.INTERVAL_MILLISECOND||triggerType == TriggerType.INTERVAL_HOUR; } @Override public Trigger build(TimingModel timingModel) { if (!(timingModel instanceof IntervalTimingMode)){ throw new TimingException("构建类型为INTERVAL定时必须传入IntervalTimingMode.class的实现类"); } //创建触发器 SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule(); Long interval = ((IntervalTimingMode) timingModel).getInterval(); Integer repeatCount = ((IntervalTimingMode) timingModel).getRepeatCount(); switch (timingModel.getType()){ case INTERVAL_MINUTE: simpleScheduleBuilder.withIntervalInMinutes(Math.toIntExact(interval)); break; case INTERVAL_HOUR: simpleScheduleBuilder.withIntervalInHours(Math.toIntExact(interval)); break; case INTERVAL_SECOND: simpleScheduleBuilder.withIntervalInSeconds(Math.toIntExact(interval)); break; case INTERVAL_MILLISECOND: simpleScheduleBuilder.withIntervalInMilliseconds(interval); break; } if (repeatCount==null){ // 无限重复 simpleScheduleBuilder.repeatForever(); }else { simpleScheduleBuilder.withRepeatCount(repeatCount); } return TriggerBuilder.newTrigger().withIdentity(timingModel.getTaskName(), timingModel.getTaskName()) .withSchedule(simpleScheduleBuilder).build(); } }3.4 构建触发器工厂
package org.demo.quartz.trigger; import org.demo.quartz.mode.TimingModel; import org.quartz.Trigger; import org.springframework.stereotype.Component; import java.util.List; @Component public class TriggerManager { private final List3. 构建定时管理类triggerFactories; public TriggerManager(List triggerFactories) { this.triggerFactories = triggerFactories; } public Trigger build(TimingModel timingModel) { for (ITriggerFactory triggerFactory : triggerFactories) { if (triggerFactory.check(timingModel.getType())) { return triggerFactory.build(timingModel); } } return null; } }
该方法包含:
- 添加定时
- 更新定时触发器
- 更新任务参数
- 删除任务
- 暂停任务
- 将暂停的任务恢复执行
- 启动所有任务
- 关闭定时任务
- 获取所有任务
package org.demo.quartz; import lombok.extern.slf4j.Slf4j; import org.demo.quartz.mode.CronTimingModel; import org.demo.quartz.mode.TimingModel; import org.demo.quartz.trigger.TriggerManager; import org.demo.quartz.exception.TimingException; import org.quartz.*; import org.quartz.impl.matchers.GroupMatcher; import org.springframework.context.annotation.Configuration; import java.lang.reflect.InvocationTargetException; import java.util.*; @Configuration @Slf4j public class QuartzTaskManager { private final Scheduler scheduler; private final Boolean initStatus; private final TriggerManager triggerManager; private static QuartzTaskManager taskManager; public QuartzTaskManager(Scheduler scheduler, TriggerManager triggerManager) { this.scheduler = scheduler; taskManager = this; boolean status = true; try { // 启动调度器 scheduler.start(); } catch (SchedulerException e) { log.error("定时器调度器启动失败,定时器不可用!", e); status = false; } initStatus = status; this.triggerManager = triggerManager; } public static QuartzTaskManager getInstance(){ return taskManager; } public void addTask(TimingModel timingModel) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, SchedulerException { checkTimingInit(); // 构建任务信息 JobDetail jobDetail = JobBuilder.newJob(timingModel.getTaskClass().getDeclaredConstructor().newInstance().getClass()) .withDescription(timingModel.getDescription()) .withIdentity(timingModel.getTaskName(), timingModel.getGroupName()) .build(); // 构建触发器 Trigger trigger = triggerManager.build(timingModel); // 将任务参数放入触发器中 if (timingModel.getParam() != null && !timingModel.getParam().isEmpty()) { trigger.getJobDataMap().putAll(timingModel.getParam()); } // 启动任务 scheduler.scheduleJob(jobDetail, trigger); } public void updateTask(TimingModel timingModel) throws SchedulerException { // 获取到任务 TriggerKey triggerKey = TriggerKey.triggerKey(timingModel.getTaskName(), timingModel.getGroupName()); // 构建触发器 Trigger trigger = triggerManager.build(timingModel); // 将任务参数放入触发器中 if (timingModel.getParam() != null && !timingModel.getParam().isEmpty()) { trigger.getJobDataMap().putAll(timingModel.getParam()); } // 将新的触发器绑定到任务标示上重新执行 scheduler.rescheduleJob(triggerKey, trigger); } public void updateTask(String taskName, String groupName, Map4. Quartz注入到SpringBootparam) throws SchedulerException { // 获取到任务 TriggerKey triggerKey = TriggerKey.triggerKey(taskName, groupName); Trigger trigger = scheduler.getTrigger(triggerKey); //修改参数 trigger.getJobDataMap().putAll(param); // 将新的触发器绑定到任务标示上重新执行 scheduler.rescheduleJob(triggerKey, trigger); } public void deleteTask(String taskName, String groupName) throws SchedulerException { // 暂停任务对应的触发器 scheduler.pauseTrigger(TriggerKey.triggerKey(taskName, groupName)); // 删除任务对应的触发器 scheduler.unscheduleJob(TriggerKey.triggerKey(taskName, groupName)); // 删除任务 scheduler.deleteJob(JobKey.jobKey(taskName, groupName)); } public void pauseTask(String taskName, String groupName) throws SchedulerException { scheduler.pauseJob(JobKey.jobKey(taskName, groupName)); } public void resumetask(String taskName, String groupName) throws SchedulerException { scheduler.resumeJob(JobKey.jobKey(taskName, groupName)); } public void startAllTasks() { try { scheduler.start(); } catch (Exception e) { throw new RuntimeException(e); } } public void shutdownAllTasks() { try { if (!scheduler.isShutdown()) { scheduler.shutdown(); } } catch (Exception e) { throw new RuntimeException(e); } } public List getTaskList() throws SchedulerException { GroupMatcher matcher = GroupMatcher.anyJobGroup(); Set jobKeys = scheduler.getJobKeys(matcher); List taskList = new ArrayList<>(); for (JobKey jobKey : jobKeys) { List extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey); for (Trigger trigger : triggers) { TimingModel timingModel; if (trigger instanceof CronTrigger) { timingModel = new CronTimingModel(null, jobKey.getName(), jobKey.getGroup(), null, ((CronTrigger) trigger).getCronexpression()); timingModel.setTaskStatus(scheduler.getTriggerState(trigger.getKey()).name()); taskList.add(timingModel); } else { log.warn("name:{},group:{}的定时任务类型未知,请拓展QuartzTaskManager.getTaskList的任务类型解析", jobKey.getName(), jobKey.getGroup()); } } } return taskList; } private void checkTimingInit() { if (!initStatus) { throw new TimingException("定时器未初始化,添加定时器失败!"); } } }
package org.demo.quartz.config; import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.scheduling.quartz.AdaptableJobFactory; import org.springframework.stereotype.Component; @Component public class TaskJobFactory extends AdaptableJobFactory { private final AutowireCapableBeanFactory capableBeanFactory; public TaskJobFactory(AutowireCapableBeanFactory capableBeanFactory) { this.capableBeanFactory = capableBeanFactory; } @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //调用父类的方法 Object jobInstance = super.createJobInstance(bundle); //进行注入 capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }5. 执行
package org.demo; import org.demo.quartz.QuartzTaskManager; import org.demo.quartz.mode.CronTimingModel; import org.demo.quartz.mode.IntervalTimingMode; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.task.TestQuartz; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.util.HashMap; @SpringBootApplication public class QuartzApplication implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(QuartzApplication.class, args); } @Override public void run(String... args) throws Exception { //构建CRON定时 //CronTimingModel cronTimingModel = new CronTimingModel(TestQuartz.class, "测试名", "测试组", "测试描述", "*/1 * * * * ?"); // 构建固定间隔定时 IntervalTimingMode intervalTimingMode = new IntervalTimingMode(TestQuartz.class, "测试名", "测试组", "测试描述", TriggerType.INTERVAL_SECOND, 5L,null); HashMap5.1 执行结果param = new HashMap<>(); param.put("paramKey","获取到参数了"); intervalTimingMode.setParam(param); QuartzTaskManager.getInstance().addTask(intervalTimingMode); } }
. ____ _ __ _ _ /\ / ___'_ __ _ _(_)_ __ __ _ ( ( )___ | '_ | '_| | '_ / _` | \/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |___, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.1) 2021-12-16 18:46:55.763 INFO 46460 --- [ main] org.demo.QuartzApplication : Starting QuartzApplication using Java 11.0.11 on xiaohandeiMac.local with PID 46460 (/Users/xiaohan/IdeaProjects/demo-quartz/target/classes started by xiaohan in /Users/xiaohan/IdeaProjects/demo-quartz) 2021-12-16 18:46:55.764 INFO 46460 --- [ main] org.demo.QuartzApplication : No active profile set, falling back to default profiles: default 2021-12-16 18:46:56.089 INFO 46460 --- [ main] org.quartz.impl.StdSchedulerFactory : Using default implementation for ThreadExecutor 2021-12-16 18:46:56.095 INFO 46460 --- [ main] org.quartz.core.SchedulerSignalerImpl : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl 2021-12-16 18:46:56.095 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : Quartz Scheduler v.2.3.2 created. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.simpl.RAMJobStore : RAMJobStore initialized. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : Scheduler meta-data: Quartz Scheduler (v2.3.2) 'quartzScheduler' with instanceId 'NON_CLUSTERED' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads. Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'quartzScheduler' initialized from an externally provided properties instance. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.2 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@2d6aca33 2021-12-16 18:46:56.099 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED started. 2021-12-16 18:46:56.147 INFO 46460 --- [ main] org.demo.QuartzApplication : Started QuartzApplication in 0.589 seconds (JVM running for 6.058) 1 2021-12-16 18:46:56.156 INFO 46460 --- [eduler_Worker-1] org.demo.quartz.task.TestQuartz : ---------------------- 任务组:测试名 任务名:测试组 任务描述:测试描述 获取参数paramKey:获取到参数了 ---------------------- 2 2021-12-16 18:47:01.155 INFO 46460 --- [eduler_Worker-2] org.demo.quartz.task.TestQuartz : ---------------------- 任务组:测试名 任务名:测试组 任务描述:测试描述 获取参数paramKey:获取到参数了 ---------------------- 3 2021-12-16 18:47:06.151 INFO 46460 --- [eduler_Worker-3] org.demo.quartz.task.TestQuartz : ---------------------- 任务组:测试名 任务名:测试组 任务描述:测试描述 获取参数paramKey:获取到参数了 ----------------------源码
Gitee
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)