From 0574f0774d49b9b84c5780f12c25a090f0b9f32d Mon Sep 17 00:00:00 2001 From: liuminglei <812934656@qq.com> Date: Fri, 11 Jan 2019 17:30:17 +0800 Subject: [PATCH 1/3] =?UTF-8?q?2.0.0=E5=88=9D=E5=A7=8B=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/xbd/quartz/DefaultQuartzJobBean.java | 112 +-- src/main/java/com/xbd/quartz/QuartzJob.java | 100 ++ .../java/com/xbd/quartz/QuartzJobBuilder.java | 133 +++ .../com/xbd/quartz/QuartzTaskHandler.java | 864 ++++++++++++++++-- .../java/com/xbd/quartz/QuartzTrigger.java | 246 +++++ .../com/xbd/quartz/QuartzTriggerBuilder.java | 231 +++++ .../handler/DefaultQuartzTaskHandler.java | 501 ++++++---- 7 files changed, 1860 insertions(+), 327 deletions(-) create mode 100644 src/main/java/com/xbd/quartz/QuartzJob.java create mode 100644 src/main/java/com/xbd/quartz/QuartzJobBuilder.java create mode 100644 src/main/java/com/xbd/quartz/QuartzTrigger.java create mode 100644 src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java diff --git a/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java b/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java index bb5338b..2d67674 100644 --- a/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java +++ b/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java @@ -1,125 +1,37 @@ package com.xbd.quartz; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import org.apache.commons.lang3.StringUtils; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationContext; import org.springframework.scheduling.quartz.QuartzJobBean; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; +import java.time.LocalDateTime; /** - *

* 默认定时任务QuartzJobBean - *

* - * @author 小不点 + * @author 刘明磊 + * @since 1.0 */ -public class DefaultQuartzJobBean extends QuartzJobBean { +public abstract class DefaultQuartzJobBean extends QuartzJobBean { private final Logger logger = LoggerFactory.getLogger(getClass()); - public final static String JOBDETAIL_KEY_TARGETCLASS = "targetClass"; - public final static String JOBDETAIL_KEY_TARGETOBJECT = "targetObject"; - public final static String JOBDETAIL_KEY_TARGETMETHOD = "targetMethod"; - public final static String JOBDETAIL_KEY_TARGETMETHOD_PARAM = "targetMethodParam"; - public final static String JOBDETAIL_VALUE_TARGETMETHOD = AbstractQuartzTask.DEFAULT_TARGETMETHOD; - - private String targetClass; - private String targetObject; - private String targetMethod; - private String targetMethodParam; + public abstract String name(); @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { - try { - if (StringUtils.isBlank(targetClass) && StringUtils.isBlank(targetObject)) { - throw new JobExecutionException("定时任务目标对象为空!"); - } - - if (StringUtils.isBlank(targetMethod)) { - throw new JobExecutionException("定时任务目标方法为空!"); - } - - Object bean; - Method m; - - if (StringUtils.isNotBlank(targetObject)) { - ApplicationContext ctx = (ApplicationContext) context.getScheduler().getContext().get("applicationContext"); - - bean = ctx.getBean(targetObject); - } else { - bean = Class.forName(targetClass).newInstance(); - } - - if (StringUtils.isBlank(targetMethodParam)) { - m = bean.getClass().getMethod(targetMethod); - - m.invoke(bean, new Object[] {}); - } else { - Object paramObject = JSON.parse(targetMethodParam); - - if (paramObject instanceof JSONObject) { - m = bean.getClass().getMethod(targetMethod, Object.class); - - m.invoke(bean, new Object[] { targetMethodParam }); - } else if (paramObject instanceof JSONArray) { - JSONArray params = (JSONArray) paramObject; - - List argClasss = new ArrayList<>(); - List args = new ArrayList<>(); - - for (Object param : params) { - argClasss.add(param.getClass()); - args.add(param); - } - - m = bean.getClass().getMethod(targetMethod, argClasss.toArray(new Class[] {})); - - m.invoke(bean, ((JSONArray) paramObject).toArray(new Object[] {})); - } - } - } catch (Exception e) { - logger.error(e.getMessage(), e); + if (this.logger.isDebugEnabled()) { + this.logger.debug("任务{}执行开始{}...", new Object[] { name(), LocalDateTime.now()}); } - } - - public String getTargetClass() { - return targetClass; - } - public void setTargetClass(String targetClass) { - this.targetClass = targetClass; - } + executeInternalInternal(context); - public String getTargetObject() { - return targetObject; - } - - public void setTargetObject(String targetObject) { - this.targetObject = targetObject; - } - - public String getTargetMethod() { - return targetMethod; - } - - public void setTargetMethod(String targetMethod) { - this.targetMethod = targetMethod; + if (this.logger.isDebugEnabled()) { + this.logger.debug("任务{}执行完成{}...", new Object[] { name(), LocalDateTime.now()}); + } } - public String getTargetMethodParam() { - return targetMethodParam; - } + protected abstract void executeInternalInternal(JobExecutionContext context) throws JobExecutionException; - public void setTargetMethodParam(String targetMethodParam) { - this.targetMethodParam = targetMethodParam; - } - } diff --git a/src/main/java/com/xbd/quartz/QuartzJob.java b/src/main/java/com/xbd/quartz/QuartzJob.java new file mode 100644 index 0000000..8415e01 --- /dev/null +++ b/src/main/java/com/xbd/quartz/QuartzJob.java @@ -0,0 +1,100 @@ +package com.xbd.quartz; + +import org.quartz.JobKey; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 定时任务实体,包含任务名称、任务分组、任务描述、任务开始时间、是否立即开始、 + * 任务结束时间、任务目标类、任务目标类SpringBean对象、任务目标类执行方法、cron表达式等属性 + * + * @author luas + * @since 2.0 + */ +public class QuartzJob implements Serializable { + + private static final long serialVersionUID = -2116518270025568628L; + + private JobKey key; + + private String description; + + private Class jobClass; + + private Map jobData; + + private boolean durability = false; + + private boolean shouldRecover = false; + + private Set triggers; + + public void addTrigger(QuartzTrigger quartzTrigger) { + if (quartzTrigger != null) { + if (this.triggers == null) { + this.triggers = new HashSet<>(); + } + + this.triggers.add(quartzTrigger); + } + } + + public JobKey getKey() { + return key; + } + + public void setKey(JobKey key) { + this.key = key; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Class getJobClass() { + return jobClass; + } + + public void setJobClass(Class jobClass) { + this.jobClass = jobClass; + } + + public Map getJobData() { + return jobData; + } + + public void setJobData(Map jobData) { + this.jobData = jobData; + } + + public boolean isDurability() { + return durability; + } + + public void setDurability(boolean durability) { + this.durability = durability; + } + + public boolean isShouldRecover() { + return shouldRecover; + } + + public void setShouldRecover(boolean shouldRecover) { + this.shouldRecover = shouldRecover; + } + + public Set getTriggers() { + return triggers; + } + + public void setTriggers(Set triggers) { + this.triggers = triggers; + } +} diff --git a/src/main/java/com/xbd/quartz/QuartzJobBuilder.java b/src/main/java/com/xbd/quartz/QuartzJobBuilder.java new file mode 100644 index 0000000..f19309e --- /dev/null +++ b/src/main/java/com/xbd/quartz/QuartzJobBuilder.java @@ -0,0 +1,133 @@ +package com.xbd.quartz; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.quartz.JobKey; +import org.quartz.utils.Key; + +public class QuartzJobBuilder { + + private JobKey key; + + private String description; + + private Class jobClass; + + private Map jobData = new HashMap<>(); + + private Set triggers = new HashSet<>(); + + private QuartzJobBuilder() { + + } + + public static QuartzJobBuilder newJob() { + return new QuartzJobBuilder(); + } + + public static QuartzJobBuilder newJob(Class jobClass) { + QuartzJobBuilder builder = new QuartzJobBuilder(); + builder.ofType(jobClass); + return builder; + } + + public QuartzJob build() { + + QuartzJob job = new QuartzJob(); + + job.setJobClass(jobClass); + job.setDescription(description); + + if (key == null) { + key = new JobKey(Key.createUniqueName(null), null); + } + + job.setKey(key); + + if(!jobData.isEmpty()) { + job.setJobData(jobData); + } + + if (!this.triggers.isEmpty()) { + job.setTriggers(this.triggers); + } + + return job; + } + + public QuartzJobBuilder withIdentity(JobKey jobKey) { + this.key = jobKey; + return this; + } + + public QuartzJobBuilder withIdentity(String name) { + key = new JobKey(name, null); + return this; + } + + public QuartzJobBuilder withIdentity(String name, String group) { + key = new JobKey(name, group); + return this; + } + + public QuartzJobBuilder withDescription(String jobDescription) { + this.description = jobDescription; + return this; + } + + public QuartzJobBuilder ofType(Class jobClazz) { + this.jobClass = jobClazz; + return this; + } + + public QuartzJobBuilder setTrigger(Set newTriggers) { + this.triggers.forEach(newTriggers::add); + this.triggers = newTriggers; + return this; + } + + public QuartzJobBuilder withTrigger(QuartzTrigger trigger) { + this.triggers.add(trigger); + return this; + } + + public QuartzJobBuilder setJobData(Map newJobData) { + this.jobData.forEach(newJobData::put); + this.jobData = newJobData; + return this; + } + + public QuartzJobBuilder usingJobData(String key, String value) { + this.jobData.put(key, value); + return this; + } + + public QuartzJobBuilder usingJobData(String key, Integer value) { + this.jobData.put(key, value); + return this; + } + + public QuartzJobBuilder usingJobData(String key, Long value) { + this.jobData.put(key, value); + return this; + } + + public QuartzJobBuilder usingJobData(String key, Double value) { + this.jobData.put(key, value); + return this; + } + + public QuartzJobBuilder usingJobData(String key, Float value) { + this.jobData.put(key, value); + return this; + } + + public QuartzJobBuilder usingJobData(String key, Boolean value) { + this.jobData.put(key, value); + return this; + } + +} diff --git a/src/main/java/com/xbd/quartz/QuartzTaskHandler.java b/src/main/java/com/xbd/quartz/QuartzTaskHandler.java index eb164fc..56d6f0c 100644 --- a/src/main/java/com/xbd/quartz/QuartzTaskHandler.java +++ b/src/main/java/com/xbd/quartz/QuartzTaskHandler.java @@ -1,157 +1,873 @@ package com.xbd.quartz; +import java.util.*; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.quartz.Calendar; import org.quartz.*; +import org.quartz.impl.matchers.GroupMatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.lang.NonNull; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +/** + * 定时任务控制器 + * + * @author 刘明磊 + * @since 1.0 + */ public abstract class QuartzTaskHandler { + protected Logger logger = LoggerFactory.getLogger(getClass()); + @NonNull protected Scheduler scheduler; /** * 动态添加任务 + *

+ * 将声明的{@code QuartzJob}添加到{@code Scheduler}中 + *

* - * @see QuartzTask + * @param quartzJob 定时任务信息 * - * @param quartzTask 定时任务信息 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob 定时任务信息 + * + * @throws SchedulerException 如果声明的定时任务不能被添加到{@code Scheduler}中,或者{@code Scheduler}内部异常 */ - public abstract void addTask(QuartzTask quartzTask) throws SchedulerException; + public abstract void addJob(QuartzJob quartzJob) throws SchedulerException; /** - * 批量动态添加任务 + * 动态添加任务 + *

+ * 将声明的{@code QuartzJob}添加到{@code Scheduler}中 + *

* - * @see QuartzTask + * @param quartzJobs 定时任务信息列表 * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob 定时任务信息 + * @see #addJob(QuartzJob) + * + * @throws SchedulerException 如果声明的定时任务不能被添加到{@code Scheduler}中,或者{@code Scheduler}内部异常 */ - public abstract void addTask(QuartzTask... quartzTasks) throws SchedulerException; + public abstract void addJob(QuartzJob... quartzJobs) throws SchedulerException; /** - * 动态更新任务 + * 动态添加任务 + *

+ * 将声明的{@code QuartzJob}更新到{@code Scheduler}中,任务可以是正在运行的状态,也没问题 + *

* - * @see QuartzTask + * @param quartzJob 定时任务信息 * - * @param quartzTask 定时任务信息 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob 定时任务信息 + * @see #addJob(QuartzJob) + * + * @throws SchedulerException 如果声明的定时任务不能被更新到{@code Scheduler}中,或者{@code Scheduler}内部异常 */ - public abstract void updateTask(QuartzTask quartzTask) throws SchedulerException; + public abstract void updateJob(QuartzJob quartzJob) throws SchedulerException; /** - * 批量动态更新任务 + * 动态添加任务 + *

+ * 将声明的{@code QuartzJob}更新到{@code Scheduler}中,任务可以是正在运行的状态,也没问题 + *

* - * @see QuartzTask + * @param quartzJobs 定时任务信息列表 * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob 定时任务信息 + * @see #updateJob(QuartzJob) + * + * @throws SchedulerException 如果声明的定时任务不能被更新到{@code Scheduler}中,或者{@code Scheduler}内部异常 */ - public abstract void updateTask(QuartzTask... quartzTasks) throws SchedulerException; + public abstract void updateJob(QuartzJob... quartzJobs) throws SchedulerException; + + public abstract void saveJob(QuartzJob quartzJob) throws SchedulerException; + + public abstract void saveJob(QuartzJob... quartzJobs) throws SchedulerException; /** - * 暂停任务 + * 暂停声明的{@code QuartzJob}任务 * - * @see QuartzTask + * @since 2.0 + * @see QuartzJob * - * @param quartzTask 定时任务信息 - * @throws SchedulerException + * @param quartzJob 定时任务信息 + * @throws SchedulerException 如果声明的定时任务不能被暂停,或者{@code Scheduler}内部异常 */ - public abstract void pauseTask(QuartzTask quartzTask) throws SchedulerException; + public abstract void pauseJob(QuartzJob quartzJob) throws SchedulerException; /** - * 批量暂停任务 + * 暂停声明的{@code QuartzJob}任务 * - * @see QuartzTask + * @since 2.0 + * @see QuartzJob + * @see #pauseJob(QuartzJob) * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException + * @param quartzJobs 定时任务信息列表 + * @throws SchedulerException 如果声明的定时任务不能被暂停,或者{@code Scheduler}内部异常 */ - public abstract void pauseTask(QuartzTask... quartzTasks) throws SchedulerException; + public abstract void pauseJob(QuartzJob... quartzJobs) throws SchedulerException; /** - * 暂停所有任务 + * 暂停声明的{@code JobKey}任务 * - * @throws SchedulerException + * @since 2.0 + * @see JobKey + * + * @param jobKey 定时任务Key标识 + * @throws SchedulerException 如果声明的定时任务不能被暂停,或者{@code Scheduler}内部异常 */ - public abstract void pauseTask() throws SchedulerException; + public abstract void pauseJob(JobKey jobKey) throws SchedulerException; + + /** + * 暂停声明的{@code JobKey}任务 + * + * @since 2.0 + * @see JobKey + * + * @param jobKeys 定时任务Key标识列表 + * @throws SchedulerException 如果声明的定时任务不能被暂停,或者{@code Scheduler}内部异常 + */ + public abstract void pauseJob(List jobKeys) throws SchedulerException; + + /** + * 暂停满足Group条件的任务 + * + * @since 2.0 + * @see GroupMatcher + * + * @param matcher Group匹配条件 + * @throws SchedulerException 如果声明的定时任务不能被暂停,或者{@code Scheduler}内部异常 + */ + public abstract void pauseJob(GroupMatcher matcher) throws SchedulerException; /** * 继续任务 * - * @see QuartzTask + *

将已暂停的任务恢复运行状态

* - * @param quartzTask 定时任务信息 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob + * + * @param quartzJob 定时任务信息 + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 */ - public abstract void resumeTask(QuartzTask quartzTask) throws SchedulerException; + public abstract void resumeJob(QuartzJob quartzJob) throws SchedulerException; /** - * 批量继续任务 + * 继续任务 * - * @see QuartzTask + *

将已暂停的任务恢复运行状态

* - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob + * @see #resumeJob(QuartzJob) + * + * @param quartzJobs 定时任务信息列表 + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 + */ + public abstract void resumeJob(QuartzJob... quartzJobs) throws SchedulerException; + + /** + * 继续任务 + * + *

将已暂停的任务恢复运行状态

+ * + * @since 2.0 + * @see QuartzJob + * + * @param jobKey 定时任务Key + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 */ - public abstract void resumeTask(QuartzTask... quartzTasks) throws SchedulerException; + public abstract void resumeJob(JobKey jobKey) throws SchedulerException; + + /** + * 继续任务 + * + *

将已暂停的任务恢复运行状态

+ * + * @since 2.0 + * @see QuartzJob + * + * @param jobKeys 定时任务Key列表 + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 + */ + public abstract void resumeJob(List jobKeys) throws SchedulerException; + + /** + * 继续任务 + * + *

将已暂停的任务恢复运行状态

+ * + * @since 2.0 + * @see GroupMatcher + * + * @param matcher Group匹配条件 + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 + */ + public abstract void resumeJob(GroupMatcher matcher) throws SchedulerException; + + /** + * 触发任务 + * + *

立即触发一次任务

+ * + * @since 2.0 + * + * @param quartzTrigger 任务Trigger + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 + */ + public abstract void triggerJob(QuartzTrigger quartzTrigger) throws SchedulerException; + + /** + * 触发任务 + * + *

立即触发一次任务

+ * + * @since 2.0 + * + * @param quartzTriggers 任务Trigger列表 + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 + */ + public abstract void triggerJob(QuartzTrigger... quartzTriggers) throws SchedulerException; + + /** + * 触发任务 + * + *

立即触发一次任务

+ * + * @since 2.0 + * + * @param jobKey 任务key + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 + */ + public abstract void triggerJob(JobKey jobKey) throws SchedulerException; + + /** + * 触发任务 + * + *

立即触发一次任务

+ * + * @since 2.0 + * + * @param jobKey 任务key + * @param jobDataMap 任务Trigger的JobData + * @throws SchedulerException 如果定时任务不能恢复,或者{@code Scheduler}内部异常 + */ + public abstract void triggerJob(JobKey jobKey, JobDataMap jobDataMap) throws SchedulerException; /** * 删除任务 * - * @see QuartzTask + *

+ * 将声明的{@code QuartzJob}从{@code Scheduler}中删除 + *

* - * @param quartzTask 定时任务信息 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob + * + * @param quartzJob 定时任务信息 + * @throws SchedulerException 如果定时任务不能被删除,或者{@code Scheduler}内部异常 */ - public abstract void deleteTask(QuartzTask quartzTask) throws SchedulerException; + public abstract void deleteJob(QuartzJob quartzJob) throws SchedulerException; /** - * 批量删除任务 + * 删除任务 * - * @see QuartzTask + *

+ * 将声明的{@code QuartzJob}从{@code Scheduler}中删除 + *

* - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException + * @since 2.0 + * @see QuartzJob + * @see #deleteJob(QuartzJob) + * + * @param quartzJobs 定时任务信息列表 + * @throws SchedulerException 如果定时任务不能被删除,或者{@code Scheduler}内部异常 + */ + public abstract void deleteJob(QuartzJob... quartzJobs) throws SchedulerException; + + /** + * 删除任务 + * + *

+ * 将声明的{@code QuartzJob}从{@code Scheduler}中删除 + *

+ * + * @since 2.0 + * @see QuartzJob + * + * @param jobKey 定时任务Key + * @throws SchedulerException 如果定时任务不能被删除,或者{@code Scheduler}内部异常 + */ + public abstract void deleteJob(JobKey jobKey) throws SchedulerException; + + /** + * 删除任务 + * + *

+ * 将声明的{@code QuartzJob}从{@code Scheduler}中删除 + *

+ * + * @since 2.0 + * @see QuartzJob + * + * @param jobKeys 定时任务Key列表 + * @throws SchedulerException 如果定时任务不能被删除,或者{@code Scheduler}内部异常 + */ + public abstract void deleteJob(List jobKeys) throws SchedulerException; + + /** + * 添加任务Trigger + * + * @param quartzTrigger 定时任务Trigger + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void addTrigger(QuartzTrigger quartzTrigger) throws SchedulerException; + + /** + * 添加任务Trigger + * + * @param quartzTriggers 定时任务Trigger列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void addTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException; + + /** + * 更新任务Trigger + * + * @param quartzTrigger 定时任务Trigger + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void updateTrigger(QuartzTrigger quartzTrigger) throws SchedulerException; + + /** + * 更新任务Trigger + * + * @param quartzTriggers 定时任务Trigger列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void updateTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException; + + /** + * 暂停任务Trigger + * + * @param quartzTrigger 定时任务Trigger + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void pauseTrigger(QuartzTrigger quartzTrigger) throws SchedulerException; + + /** + * 暂停任务Trigger + * + * @param quartzTriggers 定时任务Trigger列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void pauseTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException; + + /** + * 暂停任务Trigger + * + * @param triggerKey 定时任务TriggerKey + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void pauseTrigger(TriggerKey triggerKey) throws SchedulerException; + + /** + * 暂停任务Trigger + * + * @param triggerKeys 定时任务TriggerKey列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void pauseTrigger(List triggerKeys) throws SchedulerException; + + /** + * 暂停任务Trigger + * + * @param matcher 定时任务TriggerKey匹配条件 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void pauseTrigger(GroupMatcher matcher) throws SchedulerException; + + /** + * 暂停任务Trigger + *

+ * 将{@code Scheduler}中的所有任务暂停 + *

+ * + * @see QuartzJob 定时任务信息 + * + * @throws SchedulerException 如果定时任务不能被暂停,或者{@code Scheduler}内部异常 + */ + public abstract void pauseAll() throws SchedulerException; + + /** + * 重启任务Trigger + * + * @param quartzTrigger 定时任务Trigger + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void resumeTrigger(QuartzTrigger quartzTrigger) throws SchedulerException; + + /** + * 重启任务Trigger + * + * @param quartzTriggers 定时任务Trigger列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 */ - public abstract void deleteTask(QuartzTask... quartzTasks) throws SchedulerException; + public abstract void resumeTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException; + + /** + * 重启任务Trigger + * + * @param triggerKey 定时任务TriggerKey + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void resumeTrigger(TriggerKey triggerKey) throws SchedulerException; + + /** + * 重启任务Trigger + * + * @param triggerKeys 定时任务TriggerKey列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void resumeTrigger(List triggerKeys) throws SchedulerException; + + /** + * 重启任务Trigger + * + * @param matcher 定时任务TriggerKey匹配条件 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void resumeTrigger(GroupMatcher matcher) throws SchedulerException; + + /** + * 删除任务Trigger + * + * @param quartzTrigger 定时任务Trigger + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void deleteTrigger(QuartzTrigger quartzTrigger) throws SchedulerException; + + /** + * 删除任务Trigger + * + * @param quartzTriggers 定时任务Trigger列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void deleteTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException; + + /** + * 删除任务Trigger + * + * @param triggerKey 定时任务TriggerKey + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void deleteTrigger(TriggerKey triggerKey) throws SchedulerException; + + /** + * 删除任务Trigger + * + * @param triggerKeys 定时任务TriggerKey列表 + * + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public abstract void deleteTrigger(List triggerKeys) throws SchedulerException; + + /** + * 创建JobDetail + * + * @param quartzJob {@link QuartzJob} + * @return {@link JobDetail} + * @since 2.0 + * @throws SchedulerException {@link QuartzJob}属性错误、{@code Scheduler}内部异常 + */ + protected JobDetail createJobDetail(QuartzJob quartzJob) throws SchedulerException { + JobBuilder jobBuilder = JobBuilder + .newJob(quartzJob.getJobClass()) + .withIdentity(quartzJob.getKey()) + .withDescription(quartzJob.getDescription()) + .storeDurably(); + + if (quartzJob.getJobData() != null) { + jobBuilder.usingJobData(new JobDataMap(quartzJob.getJobData())); + } + + return jobBuilder.build(); + } + + /** + * 创建Trigger + * + * @param quartzTrigger {@link QuartzTrigger} + * @return {@link Trigger} + * @since 2.0 + * @throws SchedulerException {@link QuartzTrigger}属性错误、{@code Scheduler}内部异常 + */ + protected Trigger createTrigger(QuartzTrigger quartzTrigger) throws SchedulerException { + TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger() + .withIdentity(quartzTrigger.getKey()) + .withSchedule(initCronScheduleBuilder(quartzTrigger)); + + if (quartzTrigger.getJobKey() != null) { + triggerBuilder.forJob(quartzTrigger.getJobKey()); + } + + if (quartzTrigger.getJobData() != null) { + JobDataMap jobDataMap = new JobDataMap(); + jobDataMap.putAll(quartzTrigger.getJobData()); + triggerBuilder.usingJobData(jobDataMap); + } + + if (StringUtils.isNotEmpty(quartzTrigger.getCalendarName())) { + Calendar calendarInScheduler = this.scheduler.getCalendar(quartzTrigger.getCalendarName()); + if (calendarInScheduler == null) { + this.logger.error("Calendar{}尚未添加到Scheduler中!"); + + throw new SchedulerException("Calendar " + quartzTrigger.getCalendarName() + "尚未添加到Scheduler中!"); + } + + triggerBuilder.modifiedByCalendar(quartzTrigger.getCalendarName()); + } + + if (quartzTrigger.getStartAt() != null) { + triggerBuilder.startAt(quartzTrigger.getStartAt()); + } + + if (quartzTrigger.isStartNow()) { + triggerBuilder.startNow(); + } + + if (quartzTrigger.getEndAt() != null) { + triggerBuilder.endAt(quartzTrigger.getEndAt()); + } + + return triggerBuilder.build(); + } + + /** + * 创建Trigger + * + * @param quartzJob {@link QuartzJob} + * @return {@link Trigger}集合 + * @since 2.0 + * @throws SchedulerException {@link QuartzTrigger}属性错误、{@code Scheduler}内部异常 + */ + protected Set createTriggers(QuartzJob quartzJob) throws SchedulerException { + if (quartzJob.getTriggers() == null) { + return null; + } + + Set triggers = new HashSet<>(); + + for (QuartzTrigger quartzTrigger : quartzJob.getTriggers()) { + Trigger trigger = createTrigger(quartzTrigger); + + triggers.add(trigger); + } + + return triggers; + } + + /** + * 创建JobDetail及其Trigger集合Map + * + * @param quartzJob {@link QuartzJob} + * @return {@link JobDetail}及其{@link Trigger}集合Map + * @since 2.0 + * @throws SchedulerException {@link QuartzTrigger}属性错误、{@code Scheduler}内部异常 + */ + protected Map> createTriggersAndJobs(QuartzJob quartzJob) throws SchedulerException { + if (ObjectUtils.isEmpty(quartzJob) || CollectionUtils.isEmpty(quartzJob.getTriggers())) { + throw new SchedulerException(ObjectUtils.isEmpty(quartzJob) ? "job为空!" : "job对应的triggers为空!"); + } + + Map> triggersAndJobs = new HashMap<>(); + + JobDetail jobDetail = createJobDetail(quartzJob); + + Set triggers = createTriggers(quartzJob); + + triggersAndJobs.put(jobDetail, triggers); + + return triggersAndJobs; + } + + /** + * 创建JobDetail及其Trigger集合Map + * + * @param quartzJobs {@link QuartzJob} + * @return {@link JobDetail}及其{@link Trigger}集合Map + * @since 2.0 + * @throws SchedulerException {@link QuartzTrigger}属性错误、{@code Scheduler}内部异常 + */ + protected Map> createTriggersAndJobs(QuartzJob... quartzJobs) throws SchedulerException { + if (ObjectUtils.isEmpty(quartzJobs)) { + throw new SchedulerException("jobs为空!"); + } + + Map> triggersAndJobs = new HashMap<>(); + + for (QuartzJob quartzJob : quartzJobs) { + triggersAndJobs.putAll(createTriggersAndJobs(quartzJob)); + } + + return triggersAndJobs; + } /** * 根据定时任务信息组织CronScheduleBuilder * * @see CronScheduleBuilder - * @see QuartzTask - * - * @param quartzTask 定时任务信息 - * @return - */ - public CronScheduleBuilder initCronScheduleBuilder(QuartzTask quartzTask) { - CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartzTask.getCronExpression()); - - // 以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行 - if (quartzTask.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { - cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed(); - } else if (quartzTask.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { - // 以错过的第一个频率时间立刻开始执行,重做错过的所有频率周期后,当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行 - cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); - } else if (quartzTask.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) { - // 不触发立即执行,等待下次Cron触发频率到达时刻开始按照Cron频率依次执行 - cronScheduleBuilder.withMisfireHandlingInstructionDoNothing(); + * @see QuartzJob + * @see CronScheduleBuilder + * + * @param quartzTrigger 定时任务信息 + * @return CronScheduleBuilder 基于Cron表达式的{@link ScheduleBuilder} + */ + protected ScheduleBuilder initCronScheduleBuilder(QuartzTrigger quartzTrigger) { + ScheduleBuilder scheduleBuilder; + if (QuartzTrigger.TriggerType.SIMPLE.equals(quartzTrigger.getType())) { + SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInMilliseconds(quartzTrigger.getRepeatInterval()); + + if (quartzTrigger.getRepeatCount() == SimpleTrigger.REPEAT_INDEFINITELY) { + simpleScheduleBuilder.repeatForever(); + } else { + simpleScheduleBuilder.withRepeatCount(quartzTrigger.getRepeatCount()); + } + + if (quartzTrigger.getMisfireInstruction() == SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW) { + simpleScheduleBuilder.withMisfireHandlingInstructionFireNow(); + } else if (quartzTrigger.getMisfireInstruction() == SimpleTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { + simpleScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); + } else if (quartzTrigger.getMisfireInstruction() == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) { + simpleScheduleBuilder.withMisfireHandlingInstructionNextWithExistingCount(); + } else if (quartzTrigger.getMisfireInstruction() == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) { + simpleScheduleBuilder.withMisfireHandlingInstructionNextWithRemainingCount(); + } else if (quartzTrigger.getMisfireInstruction() == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) { + simpleScheduleBuilder.withMisfireHandlingInstructionNowWithExistingCount(); + } else if (quartzTrigger.getMisfireInstruction() == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) { + simpleScheduleBuilder.withMisfireHandlingInstructionNowWithRemainingCount(); + } + + scheduleBuilder = simpleScheduleBuilder; + } else { + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartzTrigger.getCronExpression()); + + // 以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行 + if (quartzTrigger.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { + cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed(); + } else if (quartzTrigger.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { + // 以错过的第一个频率时间立刻开始执行,重做错过的所有频率周期后,当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行 + cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); + } else if (quartzTrigger.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) { + // 不触发立即执行,等待下次Cron触发频率到达时刻开始按照Cron频率依次执行 + cronScheduleBuilder.withMisfireHandlingInstructionDoNothing(); + } + + scheduleBuilder = cronScheduleBuilder; } - return cronScheduleBuilder; + return scheduleBuilder; + } + + /** + * 根据任务名称、任务分组获取定时任务调度器中的该任务触发器 + * + * @param name 触发器名称 + * @param group 触发器分组 + * @return CronTrigger 基于Cron表达式的定时任务触发器 + * @throws SchedulerException 名称、分组为空、触发器不存在、或者{@code Scheduler}内部异常 + */ + public Trigger getTrigger(String name, String group) throws SchedulerException { + Trigger trigger = scheduler.getTrigger(new TriggerKey(name, group)); + + return trigger; + } + + /** + * 根据任务Key获取定时任务调度器中的该任务触发器 + * + * @param triggerKey 触发器Key + * @return CronTrigger 基于Cron表达式的定时任务触发器 + * @since 2.0 + * @throws SchedulerException 名称、分组为空、触发器不存在、或者{@code Scheduler}内部异常 + */ + public Trigger getTrigger(TriggerKey triggerKey) throws SchedulerException { + Trigger trigger = scheduler.getTrigger(triggerKey); + + return trigger; + } + + /** + * Get the current state of the identified {@link Trigger}. + * + * @since 2.0 + * @see Trigger.TriggerState + */ + public Trigger.TriggerState getTriggerState(String name, String group) + throws SchedulerException { + return getTriggerState(new TriggerKey(name, group)); + } + + /** + * Get the current state of the identified {@link Trigger}. + * + * @since 2.0 + * @see Trigger.TriggerState + */ + public Trigger.TriggerState getTriggerState(QuartzTrigger quartzTrigger) + throws SchedulerException { + return getTriggerState(quartzTrigger.getKey()); + } + + /** + * Get the current state of the identified {@link Trigger}. + * + * @since 2.0 + * @see Trigger.TriggerState + */ + public Trigger.TriggerState getTriggerState(TriggerKey triggerKey) + throws SchedulerException { + Assert.notNull(triggerKey, "trigger不能为空!"); + Assert.notNull(triggerKey.getName(), "trigger名称不能为空!"); + + return this.scheduler.getTriggerState(triggerKey); + } + + /** + * Add (register) the given Calendar to the Scheduler. + * + * @param updateTriggers whether or not to update existing triggers that + * referenced the already existing calendar so that they are 'correct' + * based on the new trigger. + * + * @since 2.0 + * @throws SchedulerException + * if there is an internal Scheduler error, or a Calendar with + * the same name already exists, and replace is + * false. + */ + public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) + throws SchedulerException { + this.scheduler.addCalendar(calName, calendar, replace, updateTriggers); } /** - * 根据任务名称、任务分组获取定时任务调度器中的该任务 + * Delete the identified Calendar from the Scheduler. * - * @param name - * @param group + *

+ * If removal of the Calendar would result in + * Triggers pointing to non-existent calendars, then a + * SchedulerException will be thrown. + *

+ * + * @return true if the Calendar was found and deleted. + * @since 2.0 * @throws SchedulerException + * if there is an internal Scheduler error, or one or more + * triggers reference the calendar + */ + public boolean deleteCalendar(String calName) throws SchedulerException { + return this.scheduler.deleteCalendar(calName); + } + + /** + * Get the {@link Calendar} instance with the given name. + * + * @since 2.0 + */ + public Calendar getCalendar(String calName) throws SchedulerException { + return this.scheduler.getCalendar(calName); + } + + /** + * Get the names of all registered {@link Calendar}s. + * + * @since 2.0 + */ + public List getCalendarNames() throws SchedulerException { + return this.scheduler.getCalendarNames(); + } + + /** + * 获取当前Schedulerinstance Id + * + * @return 当前Scheduler的instance Id + * @since 2.0 + * @throws SchedulerException {@code Scheduler}内部异常 + */ + public String getSchedulerInstanceId() throws SchedulerException { + return scheduler.getSchedulerInstanceId(); + } + + /** + * Determine whether a {@link Job} with the given identifier already + * exists within the scheduler. + * + * @param jobKey the identifier to check for + * @return true if a Job exists with the given identifier + * @since 2.0 + * @throws SchedulerException 内部错误 */ - public CronTrigger getTrigger(String name, String group) throws SchedulerException { - CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(new TriggerKey(name, group)); + public boolean checkExists(JobKey jobKey) throws SchedulerException { + return this.scheduler.checkExists(jobKey); + } - return cronTrigger; + /** + * Determine whether a {@link Trigger} with the given identifier already + * exists within the scheduler. + * + * @param triggerKey the identifier to check for + * @return true if a Trigger exists with the given identifier + * @since 2.0 + * @throws SchedulerException 内部错误 + */ + public boolean checkExists(TriggerKey triggerKey) throws SchedulerException { + return this.scheduler.checkExists(triggerKey); } public Scheduler getScheduler() { diff --git a/src/main/java/com/xbd/quartz/QuartzTrigger.java b/src/main/java/com/xbd/quartz/QuartzTrigger.java new file mode 100644 index 0000000..1404697 --- /dev/null +++ b/src/main/java/com/xbd/quartz/QuartzTrigger.java @@ -0,0 +1,246 @@ +package com.xbd.quartz; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +import org.quartz.JobKey; +import org.quartz.Trigger; +import org.quartz.TriggerKey; + +/** + * 定时任务触发器 + * + * @author luas + * @since 2.0 + */ +public class QuartzTrigger implements Serializable { + + private static final long serialVersionUID = 446936256465096569L; + + /** + * 定时任务触发器类别 + */ + public enum TriggerType { + + /** + * SimpleTrigger + */ + SIMPLE, + + /** + * CronTrigger + */ + CRON + + } + + private TriggerType type = TriggerType.SIMPLE; + + private JobKey jobKey; + + private TriggerKey originalKey; + + private TriggerKey key; + + private String description; + + private String calendarName; + + private Date startAt; + + private boolean startNow; + + private Date endAt; + + private Map jobData; + + /** + * 重复次数,如永久重复,则设置该值为{@link org.quartz.SimpleTrigger#REPEAT_INDEFINITELY} + */ + private int repeatCount; + + /** + * 重复时间间隔,单位:毫秒 + */ + private long repeatInterval; + + private String cronExpression; + + /** + * 任务错过触发时间执行策略 + *

+ * 通用策略 + *

+ *
    + *
  • + * MISFIRE_INSTRUCTION_SMART_POLICY
    + * Quartz框架自动选择适合的策略 + *
  • + *
  • + * MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
    + * 以错过的第一个频率时间立刻开始执行,重做错过的所有频率周期后,当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行 + *
  • + *
+ *

+ * SimpleTrigger对应的策略 + *

+ *
    + *
  • + * MISFIRE_INSTRUCTION_FIRE_NOW
    + * 立即触发调度,且忽略已经MisFire的任务。此策略只适用于只执行一次的Trigger;如repeat count {@code >} 0,则等同于策略{@link org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT} + *
  • + *
  • + * MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
    + * 将startTime设置当前时间,重新调度该任务,包括已经MissFire的任务,如果当前时间已经晚于 endTime,那么这个触发器将不会在被触发。 + *
  • + *
  • + * MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
    + * 与{@code MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT}策略一样,区别就是会忽略已经MissFire的任务 + *
  • + *
  • + * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
    + * 同{@code MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT},区别在于会忽略已经MissFire的任务,也就是说本来这个任务应该执行10次,但是已经错过了3次,那么这个任务就还会执行7次。 + *
  • + *
  • + * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
    + * 在下一次调度时间点,重新调度该任务,包括已经MissFire的任务 + *
  • + *
+ *

+ * CronTrigger对应的策略 + *

+ *
    + *
  • + * MISFIRE_INSTRUCTION_DO_NOTHING
    + * 不触发立即执行,等待下次Cron触发频率到达时刻开始按照Cron频率依次执行 + *
  • + *
  • + * MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
    + * 以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行 + *
  • + *
+ * + * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_FIRE_NOW + * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT + * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT + * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT + * @see org.quartz.SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT + * + * @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_DO_NOTHING + * @see org.quartz.CronTrigger#MISFIRE_INSTRUCTION_FIRE_ONCE_NOW + */ + private int misfireInstruction = Trigger.MISFIRE_INSTRUCTION_SMART_POLICY; + + public TriggerType getType() { + return type; + } + + public void setType(TriggerType type) { + this.type = type; + } + + public JobKey getJobKey() { + return jobKey; + } + + public void setJobKey(JobKey jobKey) { + this.jobKey = jobKey; + } + + public TriggerKey getOriginalKey() { + return originalKey; + } + + public void setOriginalKey(TriggerKey originalKey) { + this.originalKey = originalKey; + } + + public TriggerKey getKey() { + return key; + } + + public void setKey(TriggerKey key) { + this.key = key; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCalendarName() { + return calendarName; + } + + public void setCalendarName(String calendarName) { + this.calendarName = calendarName; + } + + public Date getStartAt() { + return startAt; + } + + public void setStartAt(Date startAt) { + this.startAt = startAt; + } + + public boolean isStartNow() { + return startNow; + } + + public void setStartNow(boolean startNow) { + this.startNow = startNow; + } + + public Date getEndAt() { + return endAt; + } + + public void setEndAt(Date endAt) { + this.endAt = endAt; + } + + public Map getJobData() { + return jobData; + } + + public void setJobData(Map jobData) { + this.jobData = jobData; + } + + public int getRepeatCount() { + return repeatCount; + } + + public void setRepeatCount(int repeatCount) { + this.repeatCount = repeatCount; + } + + public long getRepeatInterval() { + return repeatInterval; + } + + public void setRepeatInterval(long repeatInterval) { + this.repeatInterval = repeatInterval; + } + + public String getCronExpression() { + return cronExpression; + } + + public void setCronExpression(String cronExpression) { + this.cronExpression = cronExpression; + } + + public int getMisfireInstruction() { + return misfireInstruction; + } + + public void setMisfireInstruction(int misfireInstruction) { + this.misfireInstruction = misfireInstruction; + } +} diff --git a/src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java b/src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java new file mode 100644 index 0000000..a1b98b8 --- /dev/null +++ b/src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java @@ -0,0 +1,231 @@ +package com.xbd.quartz; + +import org.quartz.*; +import org.quartz.utils.Key; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +public class QuartzTriggerBuilder { + + private QuartzTrigger.TriggerType type = QuartzTrigger.TriggerType.SIMPLE; + + private JobKey jobKey; + + private TriggerKey originalKey; + + private TriggerKey key; + + private String description; + + private Map jobData = new HashMap<>(); + + private String calendarName; + + /** + * 重复次数,如永久重复,则设置该值为{@link SimpleTrigger#REPEAT_INDEFINITELY} + */ + private int repeatCount; + + /** + * 重复时间间隔,单位:毫秒 + */ + private long interval; + + private String cronExpression; + + private int misfireInstruction = Trigger.MISFIRE_INSTRUCTION_SMART_POLICY; + + private Date startAt; + + private boolean startNow; + + private Date endAt; + + private QuartzTriggerBuilder() { + + } + + public static QuartzTriggerBuilder newTrigger() { + return new QuartzTriggerBuilder(); + } + + public QuartzTrigger build() { + QuartzTrigger quartzTrigger = new QuartzTrigger(); + + quartzTrigger.setType(this.type); + quartzTrigger.setJobKey(this.jobKey); + quartzTrigger.setOriginalKey(this.originalKey); + + if (key == null) { + key = new TriggerKey(Key.createUniqueName(null), null); + } + + quartzTrigger.setKey(this.key); + + quartzTrigger.setDescription(this.description); + quartzTrigger.setCalendarName(this.calendarName); + quartzTrigger.setStartAt(this.startAt); + quartzTrigger.setStartNow(this.startNow); + quartzTrigger.setEndAt(this.endAt); + + if (!this.jobData.isEmpty()) { + quartzTrigger.setJobData(this.jobData); + } + + quartzTrigger.setRepeatCount(this.repeatCount); + quartzTrigger.setRepeatInterval(this.interval); + quartzTrigger.setCronExpression(this.cronExpression); + quartzTrigger.setMisfireInstruction(this.misfireInstruction); + + return quartzTrigger; + } + + public QuartzTriggerBuilder ofType(QuartzTrigger.TriggerType type) { + this.type = type; + return this; + } + + public QuartzTriggerBuilder forJob(JobKey triggerOfJobKey) { + this.jobKey = triggerOfJobKey; + return this; + } + + public QuartzTriggerBuilder forJob(String jobName) { + this.jobKey = new JobKey(jobName, null); + return this; + } + + public QuartzTriggerBuilder forJob(String jobName, String jobGroup) { + this.jobKey = new JobKey(jobName, jobGroup); + return this; + } + + public QuartzTriggerBuilder withOriginalIdentity(TriggerKey originalTriggerKey) { + this.originalKey = originalTriggerKey; + return this; + } + + public QuartzTriggerBuilder withOriginalIdentity(String originalName) { + this.originalKey = new TriggerKey(originalName, null); + return this; + } + + public QuartzTriggerBuilder withOriginalIdentity(String originalName, String originalGroup) { + this.originalKey = new TriggerKey(originalName, originalGroup); + return this; + } + + public QuartzTriggerBuilder withIdentity(TriggerKey triggerKey) { + this.key = triggerKey; + return this; + } + + public QuartzTriggerBuilder withIdentity(String name) { + this.key = new TriggerKey(name, null); + return this; + } + + public QuartzTriggerBuilder withIdentity(String name, String group) { + this.key = new TriggerKey(name, group); + return this; + } + + public QuartzTriggerBuilder withDescription(String description) { + this.description = description; + return this; + } + + public QuartzTriggerBuilder withCalendarName(String calendarName) { + this.calendarName = calendarName; + return this; + } + + public QuartzTriggerBuilder withRepeatCount(int repeatCount) { + this.repeatCount = repeatCount; + return this; + } + + public QuartzTriggerBuilder repeatForever() { + this.repeatCount = SimpleTrigger.REPEAT_INDEFINITELY; + return this; + } + + public QuartzTriggerBuilder withIntervalInSeconds(long intervalInSeconds) { + this.interval = intervalInSeconds; + return this; + } + + public QuartzTriggerBuilder withIntervalInMinutes(int intervalInMinutes) { + this.interval = intervalInMinutes * DateBuilder.MILLISECONDS_IN_MINUTE; + return this; + } + + public QuartzTriggerBuilder withIntervalInHours(int intervalInHours) { + this.interval = intervalInHours * DateBuilder.MILLISECONDS_IN_HOUR; + return this; + } + + public QuartzTriggerBuilder withCronExpression(String cronExpression) { + this.cronExpression = cronExpression; + return this; + } + + public QuartzTriggerBuilder withMisfireInstruction(int misfireInstruction) { + this.misfireInstruction = misfireInstruction; + return this; + } + + public QuartzTriggerBuilder startAt(Date startAt) { + this.startAt = startAt; + return this; + } + + public QuartzTriggerBuilder startNow(boolean startNow) { + this.startNow = startNow; + return this; + } + + public QuartzTriggerBuilder endAt(Date endAt) { + this.endAt = endAt; + return this; + } + + public QuartzTriggerBuilder setJobData(Map newJobData) { + this.jobData.forEach(newJobData::put); + this.jobData = newJobData; + return this; + } + + public QuartzTriggerBuilder usingJobData(String key, String value) { + this.jobData.put(key, value); + return this; + } + + public QuartzTriggerBuilder usingJobData(String key, Integer value) { + this.jobData.put(key, value); + return this; + } + + public QuartzTriggerBuilder usingJobData(String key, Long value) { + this.jobData.put(key, value); + return this; + } + + public QuartzTriggerBuilder usingJobData(String key, Double value) { + this.jobData.put(key, value); + return this; + } + + public QuartzTriggerBuilder usingJobData(String key, Float value) { + this.jobData.put(key, value); + return this; + } + + public QuartzTriggerBuilder usingJobData(String key, Boolean value) { + this.jobData.put(key, value); + return this; + } + +} diff --git a/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java b/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java index 1a1fc63..db96f6e 100644 --- a/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java +++ b/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java @@ -1,224 +1,419 @@ package com.xbd.quartz.handler; -import com.xbd.quartz.DefaultQuartzJobBean; -import com.xbd.quartz.QuartzTask; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.xbd.quartz.QuartzJob; import com.xbd.quartz.QuartzTaskHandler; -import org.apache.commons.lang3.StringUtils; +import com.xbd.quartz.QuartzTrigger; + +import org.apache.commons.collections.CollectionUtils; import org.quartz.*; +import org.quartz.impl.matchers.GroupMatcher; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +/** + * QuartzTaskHandler的默认实现 + * + *
+ *     SpringBoot项目
+ *     {@code @Bean}
+ *      public DefaultQuartzTaskHandler defaultQuartzTaskHandler() {
+ *          DefaultQuartzTaskHandler defaultQuartzTaskHandler = new DefaultQuartzTaskHandler();
+ *          defaultQuartzTaskHandler.setScheduler(scheduler);
+ *          return defaultQuartzTaskHandler;
+ *      }
+ *
+ *     同样也可以用在SpringMVC项目中:
+ *    {@code }
+ *         {@code }
+ *    {@code }
+ * 
+ * + * @author 刘明磊 + * @since 1.0 + */ public class DefaultQuartzTaskHandler extends QuartzTaskHandler { - public DefaultQuartzTaskHandler() { - } - /** * 动态添加任务 - * - * @see QuartzTask - * - * @param quartzTask 定时任务信息 - * @throws SchedulerException */ - public void addTask(QuartzTask quartzTask) throws SchedulerException { - JobDetail jobDetail = JobBuilder - .newJob(DefaultQuartzJobBean.class) - .withIdentity(quartzTask.getName(), quartzTask.getGroup()) - .withDescription(quartzTask.getDescription()) - .storeDurably() - .build(); - - CronScheduleBuilder cronScheduleBuilder = initCronScheduleBuilder(quartzTask); - - TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger() - .withIdentity(TriggerKey.triggerKey(quartzTask.getName(), quartzTask.getGroup())) - .withSchedule(cronScheduleBuilder) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETCLASS, quartzTask.getTargetClass()) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETOBJECT, quartzTask.getTargetObject()) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD, StringUtils.isBlank(quartzTask.getTargetMethod()) ? DefaultQuartzJobBean.JOBDETAIL_VALUE_TARGETMETHOD : quartzTask.getTargetMethod()) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD_PARAM, quartzTask.getTargetMethodParam()); - - if (quartzTask.getStartAt() != null) { - triggerBuilder.startAt(quartzTask.getStartAt()); - } + public void addJob(QuartzJob quartzJob) throws SchedulerException { + Assert.notNull(quartzJob, "job不能为空!"); + Assert.notNull(quartzJob.getJobClass(), "job class不能为空!"); + Assert.notNull(quartzJob.getKey(), "Key不能为空!"); + Assert.notNull(quartzJob.getKey().getName(), "Key名称不能为空!"); - if (quartzTask.isStartNow()) { - triggerBuilder.startNow(); - } - - if (quartzTask.getEndAt() != null) { - triggerBuilder.endAt(quartzTask.getEndAt()); - } + JobDetail jobDetail = createJobDetail(quartzJob); - CronTrigger cronTrigger = triggerBuilder.build(); + Set triggers = createTriggers(quartzJob); - scheduler.scheduleJob(jobDetail, cronTrigger); + if (CollectionUtils.isEmpty(triggers)) { + this.scheduler.addJob(jobDetail, false); + } else { + scheduler.scheduleJob(jobDetail, triggers, false); + } } /** * 批量动态添加任务 - * - * @see QuartzTask - * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException */ - public void addTask(QuartzTask... quartzTasks) throws SchedulerException { - if (quartzTasks != null) { - for (QuartzTask quartzTask : quartzTasks) { - addTask(quartzTask); - } + public void addJob(QuartzJob... quartzJobs) throws SchedulerException { + Assert.notNull(quartzJobs, "jobs不能为空!"); + + for (QuartzJob quartzJob : quartzJobs) { + addJob(quartzJob); } } /** * 动态更新任务 - * - * @see QuartzTask - * - * @param quartzTask 定时任务信息 - * @throws SchedulerException */ - public void updateTask(QuartzTask quartzTask) throws SchedulerException { - CronTrigger cronTrigger = getTrigger(quartzTask.getName(), quartzTask.getGroup()); - - CronScheduleBuilder cronScheduleBuilder = initCronScheduleBuilder(quartzTask); - - TriggerBuilder triggerBuilder = cronTrigger - .getTriggerBuilder() - .withIdentity(TriggerKey.triggerKey(quartzTask.getName(), quartzTask.getGroup())) - .withSchedule(cronScheduleBuilder) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETCLASS, quartzTask.getTargetClass()) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETOBJECT, quartzTask.getTargetObject()) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD, StringUtils.isBlank(quartzTask.getTargetMethod()) ? DefaultQuartzJobBean.JOBDETAIL_VALUE_TARGETMETHOD : quartzTask.getTargetMethod()) - .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD_PARAM, quartzTask.getTargetMethodParam()); - - if (quartzTask.getStartAt() != null) { - triggerBuilder.startAt(quartzTask.getStartAt()); - } + public void updateJob(QuartzJob quartzJob) throws SchedulerException { + saveJob(quartzJob); + } - if (quartzTask.isStartNow()) { - triggerBuilder.startNow(); - } + /** + * 批量动态更新任务 + */ + public void updateJob(QuartzJob... quartzJobs) throws SchedulerException { + saveJob(quartzJobs); + } - if (quartzTask.getEndAt() != null) { - triggerBuilder.endAt(quartzTask.getEndAt()); - } + public void saveJob(QuartzJob quartzJob) throws SchedulerException { + Assert.notNull(quartzJob, "job不能为空!"); + Assert.notNull(quartzJob.getJobClass(), "job class不能为空!"); + Assert.notNull(quartzJob.getKey(), "Key不能为空!"); + Assert.notNull(quartzJob.getKey().getName(), "Key名称不能为空!"); + + JobDetail jobDetail = createJobDetail(quartzJob); - cronTrigger = triggerBuilder.build(); + Set triggers = createTriggers(quartzJob); - scheduler.rescheduleJob(TriggerKey.triggerKey(quartzTask.getName(), quartzTask.getGroup()), cronTrigger); + if (CollectionUtils.isEmpty(triggers)) { + this.scheduler.addJob(jobDetail, true); + } else { + scheduler.scheduleJob(jobDetail, triggers, true); + } } - /** - * 批量动态更新任务 - * - * @see QuartzTask - * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException - */ - public void updateTask(QuartzTask... quartzTasks) throws SchedulerException { - if (quartzTasks != null) { - for (QuartzTask quartzTask : quartzTasks) { - updateTask(quartzTask); - } + public void saveJob(QuartzJob... quartzJobs) throws SchedulerException { + Assert.notNull(quartzJobs, "jobs不能为空!"); + + for (QuartzJob quartzJob : quartzJobs) { + saveJob(quartzJob); } } /** * 暂停任务 - * - * @see QuartzTask - * - * @param quartzTask 定时任务信息 - * @throws SchedulerException */ - public void pauseTask(QuartzTask quartzTask) throws SchedulerException { - JobKey jobKey = new JobKey(quartzTask.getName(), quartzTask.getGroup()); - scheduler.pauseJob(jobKey); + public void pauseJob(QuartzJob quartzJob) throws SchedulerException { + pauseJob(quartzJob.getKey()); } /** * 批量暂停任务 - * - * @see QuartzTask - * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException */ - public void pauseTask(QuartzTask... quartzTasks) throws SchedulerException { - if (quartzTasks != null) { - for (QuartzTask quartzTask : quartzTasks) { - pauseTask(quartzTask); - } + public void pauseJob(QuartzJob... quartzJobs) throws SchedulerException { + Assert.notNull(quartzJobs, "jobs不能为空!"); + + List jobKeys = Stream.of(quartzJobs).parallel().map(quartzJob -> quartzJob.getKey()).collect(Collectors.toList()); + + pauseJob(jobKeys); + } + + public void pauseJob(JobKey jobKey) throws SchedulerException { + Assert.notNull(jobKey, "job不能为空!"); + Assert.notNull(jobKey.getName(), "job名称不能为空!"); + + this.scheduler.pauseJob(jobKey); + } + + public void pauseJob(List jobKeys) throws SchedulerException { + Assert.notNull(jobKeys, "jobs不能为空!"); + + for (JobKey jobKey : jobKeys) { + pauseJob(jobKey); } } - /** - * 暂停所有任务 - * - * @throws SchedulerException - */ - public void pauseTask() throws SchedulerException { - scheduler.pauseAll(); + public void pauseJob(GroupMatcher matcher) throws SchedulerException { + Assert.notNull(matcher, "matcher不能为空!"); + + this.scheduler.pauseJobs(matcher); } /** * 继续任务 - * - * @see QuartzTask - * - * @param quartzTask 定时任务信息 - * @throws SchedulerException */ - public void resumeTask(QuartzTask quartzTask) throws SchedulerException { - JobKey jobKey = new JobKey(quartzTask.getName(), quartzTask.getGroup()); - scheduler.resumeJob(jobKey); + public void resumeJob(QuartzJob quartzJob) throws SchedulerException { + resumeJob(quartzJob.getKey()); } /** * 批量继续任务 - * - * @see QuartzTask - * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException */ - public void resumeTask(QuartzTask... quartzTasks) throws SchedulerException { - if (quartzTasks != null) { - for (QuartzTask quartzTask : quartzTasks) { - resumeTask(quartzTask); + public void resumeJob(QuartzJob... quartzJobs) throws SchedulerException { + Assert.notNull(quartzJobs, "jobs不能为空!"); + + List jobKeys = Stream.of(quartzJobs).parallel().map(quartzJob -> quartzJob.getKey()).collect(Collectors.toList()); + + resumeJob(jobKeys); + } + + public void resumeJob(JobKey jobKey) throws SchedulerException { + Assert.notNull(jobKey, "job不能为空!"); + Assert.notNull(jobKey.getName(), "job名称不能为空!"); + + this.scheduler.resumeJob(jobKey); + } + + public void resumeJob(List jobKeys) throws SchedulerException { + Assert.notNull(jobKeys, "jobs不能为空!"); + + for (JobKey jobKey : jobKeys) { + resumeJob(jobKey); + } + } + + public void resumeJob(GroupMatcher matcher) throws SchedulerException { + Assert.notNull(matcher, "matcher不能为空!"); + + this.scheduler.resumeJobs(matcher); + } + + public void triggerJob(QuartzTrigger quartzTrigger) throws SchedulerException { + Assert.notNull(quartzTrigger, "trigger不能为空!"); + Assert.notNull(quartzTrigger.getJobKey(), "trigger对应的jobKey不能为空!"); + Assert.notNull(quartzTrigger.getJobKey().getName(), "trigger对应的jobKey名称不能为空!"); + Assert.notNull(quartzTrigger.getKey(), "triggerKey不能为空!"); + Assert.notNull(quartzTrigger.getKey().getName(), "triggerKey名称不能为空!"); + + JobKey jobKey = quartzTrigger.getJobKey(); + + TriggerKey triggerKey = quartzTrigger.getKey(); + + JobDataMap jobDataMap = null; + + // 优先使用QuartzTrigger中的JobData + if (!ObjectUtils.isEmpty(quartzTrigger.getJobData())) { + jobDataMap = new JobDataMap(quartzTrigger.getJobData()); + } else { + // 查找该Trigger是否在Scheduler已存在且有JobData + if (checkExists(triggerKey)) { + Trigger triggerInScheduler = getTrigger(triggerKey); + jobDataMap = triggerInScheduler.getJobDataMap(); } } + + triggerJob(jobKey, jobDataMap); + } + + public void triggerJob(QuartzTrigger... quartzTriggers) throws SchedulerException { + Assert.notNull(quartzTriggers, "triggers不能为空!"); + + for (QuartzTrigger quartzTrigger : quartzTriggers) { + triggerJob(quartzTrigger); + } + } + + public void triggerJob(JobKey jobKey) throws SchedulerException { + triggerJob(jobKey, null); + } + + public void triggerJob(JobKey jobKey, JobDataMap jobDataMap) throws SchedulerException { + Assert.notNull(jobKey, "jobKey不能为空!"); + Assert.notNull(jobKey.getName(), "jobKey名称不能为空!"); + + this.scheduler.triggerJob(jobKey, jobDataMap); } /** * 删除任务 - * - * @see QuartzTask - * - * @param quartzTask 定时任务信息 - * @throws SchedulerException */ - public void deleteTask(QuartzTask quartzTask) throws SchedulerException { - JobKey jobKey = new JobKey(quartzTask.getName(), quartzTask.getGroup()); - scheduler.deleteJob(jobKey); + public void deleteJob(QuartzJob quartzJob) throws SchedulerException { + deleteJob(quartzJob.getKey()); } /** * 批量删除任务 - * - * @see QuartzTask - * - * @param quartzTasks 定时任务信息集合 - * @throws SchedulerException */ - public void deleteTask(QuartzTask... quartzTasks) throws SchedulerException { - if (quartzTasks != null) { - for (QuartzTask quartzTask : quartzTasks) { - deleteTask(quartzTask); + public void deleteJob(QuartzJob... quartzJobs) throws SchedulerException { + Assert.notNull(quartzJobs, "jobs不能为空!"); + + List jobKeys = Stream.of(quartzJobs).parallel().map(quartzJob -> quartzJob.getKey()).collect(Collectors.toList()); + + deleteJob(jobKeys); + } + + public void deleteJob(JobKey jobKey) throws SchedulerException { + Assert.notNull(jobKey, "jobKey不能为空!"); + Assert.notNull(jobKey.getName(), "jobKey名称不能为空!"); + + this.scheduler.deleteJob(jobKey); + } + + public void deleteJob(List jobKeys) throws SchedulerException { + Assert.notNull(jobKeys, "jobKeys不能为空!"); + + this.scheduler.deleteJobs(jobKeys); + } + + public void addTrigger(QuartzTrigger quartzTrigger) throws SchedulerException { + Assert.notNull(quartzTrigger, "trigger不能为空!"); + Assert.notNull(quartzTrigger.getJobKey(), "trigger对应的jobKey不能为空!"); + Assert.notNull(quartzTrigger.getJobKey().getName(), "trigger对应的jobKey名称不能为空!"); + Assert.notNull(quartzTrigger.getKey(), "triggerKey不能为空!"); + Assert.notNull(quartzTrigger.getKey().getName(), "triggerKey名称不能为空!"); + + Trigger trigger = createTrigger(quartzTrigger); + + this.scheduler.scheduleJob(trigger); + } + + public void addTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException { + Assert.notNull(quartzTriggers, "triggers不能为空!"); + + for (QuartzTrigger quartzTrigger : quartzTriggers) { + addTrigger(quartzTrigger); + } + } + + public void updateTrigger(QuartzTrigger quartzTrigger) throws SchedulerException { + Assert.notNull(quartzTrigger, "trigger不能为空!"); + Assert.notNull(quartzTrigger.getJobKey(), "trigger对应的jobKey不能为空!"); + Assert.notNull(quartzTrigger.getJobKey().getName(), "trigger对应的jobKey名称不能为空!"); + Assert.notNull(quartzTrigger.getOriginalKey(), "原Key不能为空!"); + Assert.notNull(quartzTrigger.getOriginalKey().getName(), "原Key名称不能为空!"); + Assert.notNull(quartzTrigger.getKey(), "Key不能为空!"); + Assert.notNull(quartzTrigger.getKey().getName(), "Key名称不能为空!"); + + TriggerKey originalKey = quartzTrigger.getOriginalKey(); + + if (!checkExists(originalKey)) { + throw new SchedulerException("该trigger在scheduler中不存在!"); + } else { + JobKey jobKeyOriginal = getTrigger(originalKey).getJobKey(); + JobKey jobKey = quartzTrigger.getJobKey(); + + if (!jobKeyOriginal.equals(jobKey)) { + throw new SchedulerException("trigger不能更新其对应的job!"); } } + + Trigger trigger = createTrigger(quartzTrigger); + + this.scheduler.rescheduleJob(originalKey, trigger); + } + + public void updateTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException { + Assert.notNull(quartzTriggers, "triggers不能为空!"); + + for (QuartzTrigger quartzTrigger : quartzTriggers) { + updateTrigger(quartzTrigger); + } + } + + public void pauseTrigger(QuartzTrigger quartzTrigger) throws SchedulerException { + pauseTrigger(quartzTrigger.getKey()); + } + + public void pauseTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException { + Assert.notNull(quartzTriggers, "triggers不能为空!"); + + List triggerKeys = Stream.of(quartzTriggers).parallel().map(quartzTrigger -> quartzTrigger.getKey()).collect(Collectors.toList()); + + pauseTrigger(triggerKeys); + } + + public void pauseTrigger(TriggerKey triggerKey) throws SchedulerException { + Assert.notNull(triggerKey, "trigger不能为空!"); + Assert.notNull(triggerKey.getName(), "trigger名称不能为空!"); + + this.scheduler.pauseTrigger(triggerKey); + } + + public void pauseTrigger(List triggerKeys) throws SchedulerException { + Assert.notNull(triggerKeys, "triggers不能为空!"); + + for (TriggerKey triggerKey : triggerKeys) { + pauseTrigger(triggerKey); + } + } + + public void pauseTrigger(GroupMatcher matcher) throws SchedulerException { + Assert.notNull(matcher, "matcher不能为空!"); + + this.scheduler.pauseTriggers(matcher); + } + + /** + * 暂停所有触发器 + */ + public void pauseAll() throws SchedulerException { + this.scheduler.pauseAll(); + } + + public void resumeTrigger(QuartzTrigger quartzTrigger) throws SchedulerException { + resumeTrigger(quartzTrigger.getKey()); + } + + public void resumeTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException { + Assert.notNull(quartzTriggers, "triggers不能为空!"); + + List triggerKeys = Stream.of(quartzTriggers).parallel().map(quartzTrigger -> quartzTrigger.getKey()).collect(Collectors.toList()); + + resumeTrigger(triggerKeys); + } + + public void resumeTrigger(TriggerKey triggerKey) throws SchedulerException { + Assert.notNull(triggerKey, "trigger不能为空!"); + Assert.notNull(triggerKey.getName(), "trigger名称不能为空!"); + + this.scheduler.resumeTrigger(triggerKey); + } + + public void resumeTrigger(List triggerKeys) throws SchedulerException { + Assert.notNull(triggerKeys, "triggers不能为空!"); + + for (TriggerKey triggerKey : triggerKeys) { + resumeTrigger(triggerKey); + } + } + + public void resumeTrigger(GroupMatcher matcher) throws SchedulerException { + Assert.notNull(matcher, "matcher不能为空!"); + + this.scheduler.resumeTriggers(matcher); + } + + public void deleteTrigger(QuartzTrigger quartzTrigger) throws SchedulerException { + deleteTrigger(quartzTrigger.getKey()); + } + + public void deleteTrigger(QuartzTrigger... quartzTriggers) throws SchedulerException { + Assert.notNull(quartzTriggers, "triggers不能为空!"); + + List triggerKeys = Stream.of(quartzTriggers).parallel().map(quartzTrigger -> quartzTrigger.getKey()).collect(Collectors.toList()); + + deleteTrigger(triggerKeys); + } + + public void deleteTrigger(TriggerKey triggerKey) throws SchedulerException { + Assert.notNull(triggerKey, "trigger不能为空!"); + Assert.notNull(triggerKey.getName(), "trigger名称不能为空!"); + + this.scheduler.unscheduleJob(triggerKey); + } + + public void deleteTrigger(List triggerKeys) throws SchedulerException { + Assert.notNull(triggerKeys, "triggers不能为空!"); + + this.scheduler.unscheduleJobs(triggerKeys); } } -- Gitee From c7d5decebc1f1f73ae3cef1e56ae7686e3ef139d Mon Sep 17 00:00:00 2001 From: liuminglei <812934656@qq.com> Date: Tue, 12 Nov 2019 17:17:08 +0800 Subject: [PATCH 2/3] =?UTF-8?q?QuartzListenerAware=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=B8=BAQuartzListenerRegister=EF=BC=8C=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=9B=B8=E5=85=B3README=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++----- ...zListenerAware.java => QuartzListenerRegister.java} | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/main/java/com/xbd/quartz/{QuartzListenerAware.java => QuartzListenerRegister.java} (97%) diff --git a/README.md b/README.md index 0b9ad38..a5c9487 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ sys: package com.xbd.quartz.config; import com.xbd.quartz.AutowiredSpringBeanJobFactory; -import com.xbd.quartz.QuartzListenerAware; +import com.xbd.quartz.QuartzListenerRegister; import com.xbd.quartz.handler.DefaultQuartzTaskHandler; import org.quartz.Scheduler; import org.springframework.beans.factory.annotation.Autowired; @@ -132,10 +132,10 @@ public class QuartzConfig { } @Bean - public QuartzListenerAware quartzListenerAware() { - QuartzListenerAware quartzListenerAware = new QuartzListenerAware(); - quartzListenerAware.setScheduler(scheduler()); - return quartzListenerAware; + public QuartzListenerRegister quartzListenerRegister() { + QuartzListenerRegister quartzListenerRegister = new QuartzListenerRegister(); + quartzListenerRegister.setScheduler(scheduler()); + return quartzListenerRegister; } @Bean diff --git a/src/main/java/com/xbd/quartz/QuartzListenerAware.java b/src/main/java/com/xbd/quartz/QuartzListenerRegister.java similarity index 97% rename from src/main/java/com/xbd/quartz/QuartzListenerAware.java rename to src/main/java/com/xbd/quartz/QuartzListenerRegister.java index 11802bd..d6cf92c 100644 --- a/src/main/java/com/xbd/quartz/QuartzListenerAware.java +++ b/src/main/java/com/xbd/quartz/QuartzListenerRegister.java @@ -21,7 +21,7 @@ import java.util.Map; * * @author 小不点 */ -public class QuartzListenerAware implements ApplicationContextAware, InitializingBean { +public class QuartzListenerRegister implements ApplicationContextAware, InitializingBean { private Logger log = LoggerFactory.getLogger(getClass()); -- Gitee From ba80a8de0d6ee057d95e9be2e1f0b654dde01918 Mon Sep 17 00:00:00 2001 From: liuminglei <812934656@qq.com> Date: Tue, 12 Nov 2019 17:22:45 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E9=87=8D=E6=9E=84=201=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=89=88=E6=9C=AC=E4=BF=A1=E6=81=AF=202=20?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E5=AE=8C=E5=96=84=E5=8F=8A=E8=B0=83=E6=95=B4?= =?UTF-8?q?=203=20=E6=B7=BB=E5=8A=A0=E5=85=A8=E5=B1=80JobListener=E3=80=81?= =?UTF-8?q?SchedulerListener=204=20=E6=B7=BB=E5=8A=A01.0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E7=9B=B8=E5=85=B3api=E5=B9=B6=E6=B7=BB=E5=8A=A0=E8=BF=87?= =?UTF-8?q?=E6=97=B6=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/xbd/quartz/AbstractQuartzJobBean.java | 37 +++ .../com/xbd/quartz/AbstractQuartzTask.java | 1 + .../quartz/AutowiredSpringBeanJobFactory.java | 3 +- .../com/xbd/quartz/DefaultQuartzJobBean.java | 110 +++++++- src/main/java/com/xbd/quartz/QuartzJob.java | 10 +- .../java/com/xbd/quartz/QuartzJobBuilder.java | 13 +- .../xbd/quartz/QuartzListenerRegister.java | 3 +- src/main/java/com/xbd/quartz/QuartzTask.java | 7 + .../com/xbd/quartz/QuartzTaskHandler.java | 146 +++++++++++ .../com/xbd/quartz/QuartzTriggerBuilder.java | 5 + .../quartz/configure/QuartzProperties.java | 4 + .../handler/DefaultQuartzTaskHandler.java | 248 +++++++++++++++++- .../quartz/listener/AbstractJobListener.java | 11 +- .../listener/AbstractSchedulerListener.java | 6 +- .../listener/AbstractTriggerListener.java | 9 +- .../trigger/DefaultGlobalJobListener.java | 60 +++++ .../DefaultGlobalSchedulerListener.java | 170 ++++++++++++ .../trigger/DefaultGlobalTriggerListener.java | 3 +- .../java/com/xbd/quartz/task/DemoTask.java | 1 + 19 files changed, 798 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/xbd/quartz/AbstractQuartzJobBean.java create mode 100644 src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalJobListener.java create mode 100644 src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalSchedulerListener.java rename src/{main => test}/java/com/xbd/quartz/task/DemoTask.java (98%) diff --git a/src/main/java/com/xbd/quartz/AbstractQuartzJobBean.java b/src/main/java/com/xbd/quartz/AbstractQuartzJobBean.java new file mode 100644 index 0000000..f05cc4d --- /dev/null +++ b/src/main/java/com/xbd/quartz/AbstractQuartzJobBean.java @@ -0,0 +1,37 @@ +package com.xbd.quartz; + +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import java.time.LocalDateTime; + +/** + * 默认定时任务QuartzJobBean + * + * @author 刘明磊 + * @since 1.0 + */ +public abstract class AbstractQuartzJobBean extends QuartzJobBean { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + public abstract String name(); + + @Override + protected void executeInternal(JobExecutionContext context) throws JobExecutionException { + if (this.logger.isDebugEnabled()) { + this.logger.debug("任务{}执行开始{}...", new Object[] { name(), LocalDateTime.now()}); + } + + executeInternalInternal(context); + + if (this.logger.isDebugEnabled()) { + this.logger.debug("任务{}执行完成{}...", new Object[] { name(), LocalDateTime.now()}); + } + } + + protected abstract void executeInternalInternal(JobExecutionContext context) throws JobExecutionException; + +} diff --git a/src/main/java/com/xbd/quartz/AbstractQuartzTask.java b/src/main/java/com/xbd/quartz/AbstractQuartzTask.java index 34c0d6d..4b7c6ed 100644 --- a/src/main/java/com/xbd/quartz/AbstractQuartzTask.java +++ b/src/main/java/com/xbd/quartz/AbstractQuartzTask.java @@ -1,5 +1,6 @@ package com.xbd.quartz; +@Deprecated public abstract class AbstractQuartzTask { public final static String DEFAULT_TARGETMETHOD = "execute"; diff --git a/src/main/java/com/xbd/quartz/AutowiredSpringBeanJobFactory.java b/src/main/java/com/xbd/quartz/AutowiredSpringBeanJobFactory.java index 8db31ea..0428385 100644 --- a/src/main/java/com/xbd/quartz/AutowiredSpringBeanJobFactory.java +++ b/src/main/java/com/xbd/quartz/AutowiredSpringBeanJobFactory.java @@ -6,11 +6,10 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.quartz.SpringBeanJobFactory; /** - *

* 自动装载Bean到Spring,可在JobBean中直接注入定义的Bean - *

* * @author 小不点 + * @since 1.0 */ public class AutowiredSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { diff --git a/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java b/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java index 2d67674..62953f5 100644 --- a/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java +++ b/src/main/java/com/xbd/quartz/DefaultQuartzJobBean.java @@ -1,37 +1,125 @@ package com.xbd.quartz; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang3.StringUtils; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; import org.springframework.scheduling.quartz.QuartzJobBean; -import java.time.LocalDateTime; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; /** * 默认定时任务QuartzJobBean * - * @author 刘明磊 + * @author 小不点 * @since 1.0 */ -public abstract class DefaultQuartzJobBean extends QuartzJobBean { +@Deprecated +public class DefaultQuartzJobBean extends QuartzJobBean { private final Logger logger = LoggerFactory.getLogger(getClass()); - public abstract String name(); + public final static String JOBDETAIL_KEY_TARGETCLASS = "targetClass"; + public final static String JOBDETAIL_KEY_TARGETOBJECT = "targetObject"; + public final static String JOBDETAIL_KEY_TARGETMETHOD = "targetMethod"; + public final static String JOBDETAIL_KEY_TARGETMETHOD_PARAM = "targetMethodParam"; + public final static String JOBDETAIL_VALUE_TARGETMETHOD = AbstractQuartzTask.DEFAULT_TARGETMETHOD; + + private String targetClass; + private String targetObject; + private String targetMethod; + private String targetMethodParam; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { - if (this.logger.isDebugEnabled()) { - this.logger.debug("任务{}执行开始{}...", new Object[] { name(), LocalDateTime.now()}); - } + try { + if (StringUtils.isBlank(targetClass) && StringUtils.isBlank(targetObject)) { + throw new JobExecutionException("定时任务目标对象为空!"); + } + + if (StringUtils.isBlank(targetMethod)) { + throw new JobExecutionException("定时任务目标方法为空!"); + } + + Object bean; + Method m; + + if (StringUtils.isNotBlank(targetObject)) { + ApplicationContext ctx = (ApplicationContext) context.getScheduler().getContext().get("applicationContext"); + + bean = ctx.getBean(targetObject); + } else { + bean = Class.forName(targetClass).newInstance(); + } + + if (StringUtils.isBlank(targetMethodParam)) { + m = bean.getClass().getMethod(targetMethod); - executeInternalInternal(context); + m.invoke(bean, new Object[] {}); + } else { + Object paramObject = JSON.parse(targetMethodParam); - if (this.logger.isDebugEnabled()) { - this.logger.debug("任务{}执行完成{}...", new Object[] { name(), LocalDateTime.now()}); + if (paramObject instanceof JSONObject) { + m = bean.getClass().getMethod(targetMethod, Object.class); + + m.invoke(bean, new Object[] { targetMethodParam }); + } else if (paramObject instanceof JSONArray) { + JSONArray params = (JSONArray) paramObject; + + List argClasss = new ArrayList<>(); + List args = new ArrayList<>(); + + for (Object param : params) { + argClasss.add(param.getClass()); + args.add(param); + } + + m = bean.getClass().getMethod(targetMethod, argClasss.toArray(new Class[] {})); + + m.invoke(bean, ((JSONArray) paramObject).toArray(new Object[] {})); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); } } - protected abstract void executeInternalInternal(JobExecutionContext context) throws JobExecutionException; + public String getTargetClass() { + return targetClass; + } + + public void setTargetClass(String targetClass) { + this.targetClass = targetClass; + } + + public String getTargetObject() { + return targetObject; + } + + public void setTargetObject(String targetObject) { + this.targetObject = targetObject; + } + + public String getTargetMethod() { + return targetMethod; + } + + public void setTargetMethod(String targetMethod) { + this.targetMethod = targetMethod; + } + + public String getTargetMethodParam() { + return targetMethodParam; + } + + public void setTargetMethodParam(String targetMethodParam) { + this.targetMethodParam = targetMethodParam; + } } diff --git a/src/main/java/com/xbd/quartz/QuartzJob.java b/src/main/java/com/xbd/quartz/QuartzJob.java index 8415e01..a456b4b 100644 --- a/src/main/java/com/xbd/quartz/QuartzJob.java +++ b/src/main/java/com/xbd/quartz/QuartzJob.java @@ -8,8 +8,8 @@ import java.util.Map; import java.util.Set; /** - * 定时任务实体,包含任务名称、任务分组、任务描述、任务开始时间、是否立即开始、 - * 任务结束时间、任务目标类、任务目标类SpringBean对象、任务目标类执行方法、cron表达式等属性 + * 定时任务实体 + *

包含JobKey、description、jobClass、jobData、durability、shouldRecover、triggers. * * @author luas * @since 2.0 @@ -22,7 +22,7 @@ public class QuartzJob implements Serializable { private String description; - private Class jobClass; + private Class jobClass; private Map jobData; @@ -58,11 +58,11 @@ public class QuartzJob implements Serializable { this.description = description; } - public Class getJobClass() { + public Class getJobClass() { return jobClass; } - public void setJobClass(Class jobClass) { + public void setJobClass(Class jobClass) { this.jobClass = jobClass; } diff --git a/src/main/java/com/xbd/quartz/QuartzJobBuilder.java b/src/main/java/com/xbd/quartz/QuartzJobBuilder.java index f19309e..3ab1814 100644 --- a/src/main/java/com/xbd/quartz/QuartzJobBuilder.java +++ b/src/main/java/com/xbd/quartz/QuartzJobBuilder.java @@ -8,13 +8,18 @@ import java.util.Set; import org.quartz.JobKey; import org.quartz.utils.Key; +/** + * {@code QuartzJob} to {@link org.quartz.JobDetail} + * @author luas + * @since 2.0 + */ public class QuartzJobBuilder { private JobKey key; private String description; - private Class jobClass; + private Class jobClass; private Map jobData = new HashMap<>(); @@ -28,9 +33,9 @@ public class QuartzJobBuilder { return new QuartzJobBuilder(); } - public static QuartzJobBuilder newJob(Class jobClass) { + public static QuartzJobBuilder newJob(Class jobClass) { QuartzJobBuilder builder = new QuartzJobBuilder(); - builder.ofType(jobClass); + builder.forJob(jobClass); return builder; } @@ -78,7 +83,7 @@ public class QuartzJobBuilder { return this; } - public QuartzJobBuilder ofType(Class jobClazz) { + public QuartzJobBuilder forJob(Class jobClazz) { this.jobClass = jobClazz; return this; } diff --git a/src/main/java/com/xbd/quartz/QuartzListenerRegister.java b/src/main/java/com/xbd/quartz/QuartzListenerRegister.java index d6cf92c..be4ffc9 100644 --- a/src/main/java/com/xbd/quartz/QuartzListenerRegister.java +++ b/src/main/java/com/xbd/quartz/QuartzListenerRegister.java @@ -15,11 +15,10 @@ import org.springframework.context.ApplicationContextAware; import java.util.Map; /** - *

* JobListener、SchedulerListener、TriggerListener自动注册监听 - *

* * @author 小不点 + * @since 1.0 */ public class QuartzListenerRegister implements ApplicationContextAware, InitializingBean { diff --git a/src/main/java/com/xbd/quartz/QuartzTask.java b/src/main/java/com/xbd/quartz/QuartzTask.java index f4ccdf7..f99fec8 100644 --- a/src/main/java/com/xbd/quartz/QuartzTask.java +++ b/src/main/java/com/xbd/quartz/QuartzTask.java @@ -3,6 +3,13 @@ package com.xbd.quartz; import java.io.Serializable; import java.util.Date; +/** + * 定时任务实体 + *

此类已不再使用,请使用{@link QuartzJob}、{@link QuartzTrigger}组织定时任务. + * @author luas + * @since 1.0 + */ +@Deprecated public class QuartzTask implements Serializable { private String name; diff --git a/src/main/java/com/xbd/quartz/QuartzTaskHandler.java b/src/main/java/com/xbd/quartz/QuartzTaskHandler.java index 56d6f0c..73631fe 100644 --- a/src/main/java/com/xbd/quartz/QuartzTaskHandler.java +++ b/src/main/java/com/xbd/quartz/QuartzTaskHandler.java @@ -26,6 +26,152 @@ public abstract class QuartzTaskHandler { @NonNull protected Scheduler scheduler; + /** + * 动态添加任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void addTask(QuartzTask quartzTask) throws SchedulerException; + + /** + * 批量动态添加任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void addTask(QuartzTask... quartzTasks) throws SchedulerException; + + /** + * 动态更新任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void updateTask(QuartzTask quartzTask) throws SchedulerException; + + /** + * 批量动态更新任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void updateTask(QuartzTask... quartzTasks) throws SchedulerException; + + /** + * 暂停任务 + * + * @see QuartzTask + * + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void pauseTask(QuartzTask quartzTask) throws SchedulerException; + + /** + * 批量暂停任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void pauseTask(QuartzTask... quartzTasks) throws SchedulerException; + + /** + * 暂停所有任务 + * + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void pauseTask() throws SchedulerException; + + /** + * 继续任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void resumeTask(QuartzTask quartzTask) throws SchedulerException; + + /** + * 批量继续任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void resumeTask(QuartzTask... quartzTasks) throws SchedulerException; + + /** + * 删除任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void deleteTask(QuartzTask quartzTask) throws SchedulerException; + + /** + * 批量删除任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public abstract void deleteTask(QuartzTask... quartzTasks) throws SchedulerException; + + /** + * 根据定时任务信息组织CronScheduleBuilder + * + * @see CronScheduleBuilder + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @since 1.0 + */ + @Deprecated + public CronScheduleBuilder initCronScheduleBuilder(QuartzTask quartzTask) { + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartzTask.getCronExpression()); + + // 以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行 + if (quartzTask.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) { + cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed(); + } else if (quartzTask.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) { + // 以错过的第一个频率时间立刻开始执行,重做错过的所有频率周期后,当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行 + cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); + } else if (quartzTask.getMisfireInstruction() == CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) { + // 不触发立即执行,等待下次Cron触发频率到达时刻开始按照Cron频率依次执行 + cronScheduleBuilder.withMisfireHandlingInstructionDoNothing(); + } + + return cronScheduleBuilder; + } + /** * 动态添加任务 *

diff --git a/src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java b/src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java index a1b98b8..e37b7ec 100644 --- a/src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java +++ b/src/main/java/com/xbd/quartz/QuartzTriggerBuilder.java @@ -7,6 +7,11 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; +/** + * {@code QuartzTrigger} to {@link Trigger} + * @author luas + * @since 2.0 + */ public class QuartzTriggerBuilder { private QuartzTrigger.TriggerType type = QuartzTrigger.TriggerType.SIMPLE; diff --git a/src/main/java/com/xbd/quartz/configure/QuartzProperties.java b/src/main/java/com/xbd/quartz/configure/QuartzProperties.java index cb376ad..3b113c9 100644 --- a/src/main/java/com/xbd/quartz/configure/QuartzProperties.java +++ b/src/main/java/com/xbd/quartz/configure/QuartzProperties.java @@ -3,6 +3,10 @@ package com.xbd.quartz.configure; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.io.Resource; +/** + * @author luas + * @since 1.0 + */ @ConfigurationProperties(prefix = "sys.quartz") public class QuartzProperties { diff --git a/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java b/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java index db96f6e..3669e3d 100644 --- a/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java +++ b/src/main/java/com/xbd/quartz/handler/DefaultQuartzTaskHandler.java @@ -5,39 +5,263 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.xbd.quartz.QuartzJob; -import com.xbd.quartz.QuartzTaskHandler; -import com.xbd.quartz.QuartzTrigger; +import com.xbd.quartz.*; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.quartz.*; import org.quartz.impl.matchers.GroupMatcher; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** - * QuartzTaskHandler的默认实现 - * + * {@code QuartzTaskHandler}的默认实现 + *

配置方式如下: *

- *     SpringBoot项目
- *     {@code @Bean}
+ *    java配置:
+ *    {@code
+ *      @Bean
  *      public DefaultQuartzTaskHandler defaultQuartzTaskHandler() {
  *          DefaultQuartzTaskHandler defaultQuartzTaskHandler = new DefaultQuartzTaskHandler();
  *          defaultQuartzTaskHandler.setScheduler(scheduler);
  *          return defaultQuartzTaskHandler;
  *      }
+ *    }
  *
- *     同样也可以用在SpringMVC项目中:
- *    {@code }
- *         {@code }
- *    {@code }
+ *    xml配置:
+ *    {@code
+ *      
+ *          
+ *      
+ *    }
  * 
* - * @author 刘明磊 + * @author luas * @since 1.0 */ public class DefaultQuartzTaskHandler extends QuartzTaskHandler { + /** + * 动态添加任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void addTask(QuartzTask quartzTask) throws SchedulerException { + JobDetail jobDetail = JobBuilder + .newJob(DefaultQuartzJobBean.class) + .withIdentity(quartzTask.getName(), quartzTask.getGroup()) + .withDescription(quartzTask.getDescription()) + .storeDurably() + .build(); + + CronScheduleBuilder cronScheduleBuilder = initCronScheduleBuilder(quartzTask); + + TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger() + .withIdentity(TriggerKey.triggerKey(quartzTask.getName(), quartzTask.getGroup())) + .withSchedule(cronScheduleBuilder) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETCLASS, quartzTask.getTargetClass()) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETOBJECT, quartzTask.getTargetObject()) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD, StringUtils.isBlank(quartzTask.getTargetMethod()) ? DefaultQuartzJobBean.JOBDETAIL_VALUE_TARGETMETHOD : quartzTask.getTargetMethod()) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD_PARAM, quartzTask.getTargetMethodParam()); + + if (quartzTask.getStartAt() != null) { + triggerBuilder.startAt(quartzTask.getStartAt()); + } + + if (quartzTask.isStartNow()) { + triggerBuilder.startNow(); + } + + if (quartzTask.getEndAt() != null) { + triggerBuilder.endAt(quartzTask.getEndAt()); + } + + CronTrigger cronTrigger = triggerBuilder.build(); + + scheduler.scheduleJob(jobDetail, cronTrigger); + } + + /** + * 批量动态添加任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void addTask(QuartzTask... quartzTasks) throws SchedulerException { + if (quartzTasks != null) { + for (QuartzTask quartzTask : quartzTasks) { + addTask(quartzTask); + } + } + } + + /** + * 动态更新任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void updateTask(QuartzTask quartzTask) throws SchedulerException { + CronTrigger cronTrigger = (CronTrigger) getTrigger(quartzTask.getName(), quartzTask.getGroup()); + + CronScheduleBuilder cronScheduleBuilder = initCronScheduleBuilder(quartzTask); + + TriggerBuilder triggerBuilder = cronTrigger + .getTriggerBuilder() + .withIdentity(TriggerKey.triggerKey(quartzTask.getName(), quartzTask.getGroup())) + .withSchedule(cronScheduleBuilder) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETCLASS, quartzTask.getTargetClass()) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETOBJECT, quartzTask.getTargetObject()) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD, StringUtils.isBlank(quartzTask.getTargetMethod()) ? DefaultQuartzJobBean.JOBDETAIL_VALUE_TARGETMETHOD : quartzTask.getTargetMethod()) + .usingJobData(DefaultQuartzJobBean.JOBDETAIL_KEY_TARGETMETHOD_PARAM, quartzTask.getTargetMethodParam()); + + if (quartzTask.getStartAt() != null) { + triggerBuilder.startAt(quartzTask.getStartAt()); + } + + if (quartzTask.isStartNow()) { + triggerBuilder.startNow(); + } + + if (quartzTask.getEndAt() != null) { + triggerBuilder.endAt(quartzTask.getEndAt()); + } + + cronTrigger = triggerBuilder.build(); + + scheduler.rescheduleJob(TriggerKey.triggerKey(quartzTask.getName(), quartzTask.getGroup()), cronTrigger); + } + + /** + * 批量动态更新任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void updateTask(QuartzTask... quartzTasks) throws SchedulerException { + if (quartzTasks != null) { + for (QuartzTask quartzTask : quartzTasks) { + updateTask(quartzTask); + } + } + } + + /** + * 暂停任务 + * + * @see QuartzTask + * + * @param quartzTask 定时任务信息 + * @throws SchedulerException + */ + public void pauseTask(QuartzTask quartzTask) throws SchedulerException { + JobKey jobKey = new JobKey(quartzTask.getName(), quartzTask.getGroup()); + scheduler.pauseJob(jobKey); + } + + /** + * 批量暂停任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void pauseTask(QuartzTask... quartzTasks) throws SchedulerException { + if (quartzTasks != null) { + for (QuartzTask quartzTask : quartzTasks) { + pauseTask(quartzTask); + } + } + } + + /** + * 暂停所有任务 + * + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void pauseTask() throws SchedulerException { + scheduler.pauseAll(); + } + + /** + * 继续任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void resumeTask(QuartzTask quartzTask) throws SchedulerException { + JobKey jobKey = new JobKey(quartzTask.getName(), quartzTask.getGroup()); + scheduler.resumeJob(jobKey); + } + + /** + * 批量继续任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void resumeTask(QuartzTask... quartzTasks) throws SchedulerException { + if (quartzTasks != null) { + for (QuartzTask quartzTask : quartzTasks) { + resumeTask(quartzTask); + } + } + } + + /** + * 删除任务 + * + * @see QuartzTask + * @param quartzTask 定时任务信息 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void deleteTask(QuartzTask quartzTask) throws SchedulerException { + JobKey jobKey = new JobKey(quartzTask.getName(), quartzTask.getGroup()); + scheduler.deleteJob(jobKey); + } + + /** + * 批量删除任务 + * + * @see QuartzTask + * @param quartzTasks 定时任务信息集合 + * @throws SchedulerException + * @since 1.0 + */ + @Deprecated + public void deleteTask(QuartzTask... quartzTasks) throws SchedulerException { + if (quartzTasks != null) { + for (QuartzTask quartzTask : quartzTasks) { + deleteTask(quartzTask); + } + } + } + /** * 动态添加任务 */ diff --git a/src/main/java/com/xbd/quartz/listener/AbstractJobListener.java b/src/main/java/com/xbd/quartz/listener/AbstractJobListener.java index 2a2f84f..a669916 100644 --- a/src/main/java/com/xbd/quartz/listener/AbstractJobListener.java +++ b/src/main/java/com/xbd/quartz/listener/AbstractJobListener.java @@ -4,20 +4,21 @@ import org.quartz.JobListener; import org.quartz.Matcher; import org.quartz.TriggerKey; import org.quartz.impl.matchers.EverythingMatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - *

- * 自定义JobListener,可匹配任务。定义并配置之后,系统可自动注册 - *

+ *

自定义JobListener,可匹配任务。定义并配置之后,系统可自动注册 * * @author 小不点 + * @since 1.0 */ public abstract class AbstractJobListener implements JobListener { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + /** - *

* 返回匹配某一、某些Job的匹配策略 - *

*/ public Matcher matcher() { return EverythingMatcher.allTriggers(); diff --git a/src/main/java/com/xbd/quartz/listener/AbstractSchedulerListener.java b/src/main/java/com/xbd/quartz/listener/AbstractSchedulerListener.java index aebcaa9..cc84912 100644 --- a/src/main/java/com/xbd/quartz/listener/AbstractSchedulerListener.java +++ b/src/main/java/com/xbd/quartz/listener/AbstractSchedulerListener.java @@ -1,15 +1,17 @@ package com.xbd.quartz.listener; import org.quartz.SchedulerListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - *

* 自定义SchedulerListener。定义并配置之后,系统可自动注册 - *

* * @author 小不点 + * @since 1.0 */ public abstract class AbstractSchedulerListener implements SchedulerListener { + protected final Logger logger = LoggerFactory.getLogger(getClass()); } diff --git a/src/main/java/com/xbd/quartz/listener/AbstractTriggerListener.java b/src/main/java/com/xbd/quartz/listener/AbstractTriggerListener.java index a7508f3..f99ca04 100644 --- a/src/main/java/com/xbd/quartz/listener/AbstractTriggerListener.java +++ b/src/main/java/com/xbd/quartz/listener/AbstractTriggerListener.java @@ -4,20 +4,21 @@ import org.quartz.Matcher; import org.quartz.TriggerKey; import org.quartz.TriggerListener; import org.quartz.impl.matchers.EverythingMatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - *

* 自定义TriggerListener,可匹配任务。定义并配置之后,系统可自动注册 - *

* * @author 小不点 + * @since 1.0 */ public abstract class AbstractTriggerListener implements TriggerListener { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + /** - *

* 返回匹配某一、某些Trigger的匹配策略 - *

*/ public Matcher matcher() { return EverythingMatcher.allTriggers(); diff --git a/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalJobListener.java b/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalJobListener.java new file mode 100644 index 0000000..3b78e6b --- /dev/null +++ b/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalJobListener.java @@ -0,0 +1,60 @@ +package com.xbd.quartz.listener.trigger; + +import com.xbd.quartz.listener.AbstractJobListener; + +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.Matcher; +import org.quartz.TriggerKey; + +import java.time.LocalDateTime; + +/** + * 默认全局JobListener + * + * @author luas + * @since 4.3 + */ +public class DefaultGlobalJobListener extends AbstractJobListener { + + @Override + public String getName() { + return "defaultGlobalJobListener"; + } + + @Override + public Matcher matcher() { + return super.matcher(); + } + + @Override + public void jobToBeExecuted(JobExecutionContext context) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 即将执行", new Object[] { context.getJobDetail() }); + } + } + + @Override + public void jobExecutionVetoed(JobExecutionContext context) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 于 {} 被否决,不再执行", + new Object[] { context.getJobDetail(), LocalDateTime.now() }); + } + } + + @Override + public void jobWasExecuted(JobExecutionContext context, + JobExecutionException jobException) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 于 {} 执行,", + new Object[] { context.getJobDetail(), LocalDateTime.now() }); + + if (jobException != null) { + this.logger.debug("Job {} 执行中发生异常,异常信息为 {},", + new Object[] { context.getJobDetail(), jobException }); + } + } + + } + +} diff --git a/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalSchedulerListener.java b/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalSchedulerListener.java new file mode 100644 index 0000000..c156ad1 --- /dev/null +++ b/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalSchedulerListener.java @@ -0,0 +1,170 @@ +package com.xbd.quartz.listener.trigger; + +import com.xbd.quartz.listener.AbstractSchedulerListener; + +import org.quartz.*; + +import java.time.LocalDateTime; + +/** + * 默认全局SchedulerListener + * + * @author luas + * @since 4.3 + */ +public class DefaultGlobalSchedulerListener extends AbstractSchedulerListener { + + @Override + public void jobScheduled(Trigger trigger) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 所属 Trigger {} 于 {} 执行调度。", new Object[] { + trigger.getJobKey(), trigger.getKey(), LocalDateTime.now() }); + } + } + + @Override + public void jobUnscheduled(TriggerKey triggerKey) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Trigger {} 未执行调度。", new Object[] { triggerKey }); + } + } + + @Override + public void triggerFinalized(Trigger trigger) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 所属 Trigger {} 于 {} 调度期结束,不再调度。", new Object[] { + trigger.getJobKey(), trigger.getKey(), LocalDateTime.now() }); + } + } + + @Override + public void triggerPaused(TriggerKey triggerKey) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Trigger {} 于 {} 暂停调度。", + new Object[] { triggerKey, LocalDateTime.now() }); + } + } + + @Override + public void triggersPaused(String triggerGroup) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("TriggerGroup {} 于 {} 暂停调度。", + new Object[] { triggerGroup, LocalDateTime.now() }); + } + } + + @Override + public void triggerResumed(TriggerKey triggerKey) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Trigger {} 于 {} 恢复调度。", + new Object[] { triggerKey, LocalDateTime.now() }); + } + } + + @Override + public void triggersResumed(String triggerGroup) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("TriggerGroup {} 于 {} 恢复调度。", + new Object[] { triggerGroup, LocalDateTime.now() }); + } + } + + @Override + public void jobAdded(JobDetail jobDetail) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 于 {} 添加到调度器中。", + new Object[] { jobDetail, LocalDateTime.now() }); + } + } + + @Override + public void jobDeleted(JobKey jobKey) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 于 {} 删除。", + new Object[] { jobKey, LocalDateTime.now() }); + } + } + + @Override + public void jobPaused(JobKey jobKey) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 于 {} 暂停调度。", + new Object[] { jobKey, LocalDateTime.now() }); + } + } + + @Override + public void jobsPaused(String jobGroup) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("JobGroup {} 于 {} 暂停调度。", + new Object[] { jobGroup, LocalDateTime.now() }); + } + } + + @Override + public void jobResumed(JobKey jobKey) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("Job {} 于 {} 恢复调度。", + new Object[] { jobKey, LocalDateTime.now() }); + } + } + + @Override + public void jobsResumed(String jobGroup) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("JobGroup {} 于 {} 恢复调度。", + new Object[] { jobGroup, LocalDateTime.now() }); + } + } + + @Override + public void schedulerError(String msg, SchedulerException cause) { + if (this.logger.isDebugEnabled()) { + this.logger.debug("调度器 于 {} 发生错误,错误信息 {},异常 {}。", + new Object[] { LocalDateTime.now(), msg, cause }); + } + } + + @Override + public void schedulerInStandbyMode() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("调度器 于 {} 处于待命状态。", new Object[] { LocalDateTime.now() }); + } + } + + @Override + public void schedulerStarted() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("调度器 于 {} 启动。", new Object[] { LocalDateTime.now() }); + } + } + + @Override + public void schedulerStarting() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("调度器启动中。", new Object[] { LocalDateTime.now() }); + } + } + + @Override + public void schedulerShutdown() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("调度器 于 {} 关闭。", new Object[] { LocalDateTime.now() }); + } + } + + @Override + public void schedulerShuttingdown() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("调度器关闭中。", new Object[] { LocalDateTime.now() }); + } + } + + @Override + public void schedulingDataCleared() { + if (this.logger.isDebugEnabled()) { + this.logger.debug("调度器于 {} 数据清空。", new Object[] { LocalDateTime.now() }); + } + } + +} diff --git a/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalTriggerListener.java b/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalTriggerListener.java index 82ce38b..f5ba209 100644 --- a/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalTriggerListener.java +++ b/src/main/java/com/xbd/quartz/listener/trigger/DefaultGlobalTriggerListener.java @@ -8,11 +8,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - *

* 默认全局TriggerListener - *

* * @author 小不点 + * @since 1.0 */ public class DefaultGlobalTriggerListener extends AbstractTriggerListener { diff --git a/src/main/java/com/xbd/quartz/task/DemoTask.java b/src/test/java/com/xbd/quartz/task/DemoTask.java similarity index 98% rename from src/main/java/com/xbd/quartz/task/DemoTask.java rename to src/test/java/com/xbd/quartz/task/DemoTask.java index 08cac52..160588a 100644 --- a/src/main/java/com/xbd/quartz/task/DemoTask.java +++ b/src/test/java/com/xbd/quartz/task/DemoTask.java @@ -7,6 +7,7 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component +@Deprecated public class DemoTask extends AbstractQuartzTask { private Logger logger = LoggerFactory.getLogger(getClass()); -- Gitee