0
点赞
收藏
分享

微信扫一扫

定时任务Quartz


定时任务Quartz

因为公司内部项目有使用定时任务管理的场景,所以对定时任务进行技术考察。根据当下的分布式定时任务管理工具相对较多,主要选取主流技术xxl-job,elastic-job,Quartz三种技术。
经过技术对比三种最终选择Quartz,原因如下:

  1. 首先进行xxl-job和elastic-job对比,这两种使用层面相似,都支持分布式切片,提供了管理界面,还有一些高级特性,扩容,降级等等处理。但是elastic-job使用了zookeeper学习成本更高,且如今不在维护了,在这两个前提下,排除了elastic-job,选择xxl-job。
  2. 在进行对比xxl-job和Quartz技术,Quartz相对轻量,使用对外接口,学习成本也比较低,但是功能不是十分强大,也没有页面支持。在比较下Quartz更适合现在的项目阶段,可以手动添加管理界面到系统中,无需管理多个项目。

使用简单Dome

public class TestQuartz {
public static void main(String[] args) throws SchedulerException {

//创建一个scheduler StdSchedulerFactory继承于SchedulerFactory
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

//Scheduler是整个Quartz的核心内容
scheduler.getContext().put("key", "value");

//创建一个Trigger TriggerBuilder可以通过构建模式创建Trigger对象
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.usingJobData("t1", "tv1")
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)
.repeatForever()).build();

//Trigger中JobDataMap属性用于存放特定属性
trigger.getJobDataMap().put("t2", "tv2");

//创建一个job JobBuilder可通过构建模式创建JobDetail对象
JobDetail job = JobBuilder.newJob(HelloJob.class)
.usingJobData("j1", "jv1")
.withIdentity("myjob", "mygroup").build();

//JobDetail中JobDataMap属性用于存放特定属性
job.getJobDataMap().put("j2", "jv2");

//注册job,trigger并启动scheduler
scheduler.scheduleJob(job,trigger);

//启动定时任务
scheduler.start();
}
}

核心结构

在上面的dome中,可以看到整个定时任务的核心就在Scheduler,Job,Trigger中展开,下面介绍相关内容。

Scheduler

与调度程序交互的主要API,可存放job和trigger

生命周期

从 SchedulerFactory 创建它时开始,到 Scheduler 调用shutdown() 方法时结束;Scheduler 被创建后,可以增加、删除和列举 Job 和Trigger,以及执行其它与调度相关的操作(如暂停 Trigger)。但是,Scheduler 只有在调用 start() 方法后,才会真正地触发 trigger(即执行 job)

Job

你想要调度器执行的任务组件需要实现的接口

public interface Job {
void execute(JobExecutionContext var1) throws JobExecutionException;
}

JobDetail

处理Job实例所包含的属性

public interface JobDetail extends Serializable, Cloneable {
JobKey getKey();

String getDescription();

Class<? extends Job> getJobClass();

JobDataMap getJobDataMap();

boolean isDurable();

boolean isPersistJobDataAfterExecution();

boolean isConcurrentExectionDisallowed();

boolean requestsRecovery();

Object clone();

JobBuilder getJobBuilder();
}

JobDetail中JobDataMap属性是核心内容,JobDataMap中可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据;

JobDataMap是Java Map接口的一个实现,额外增加了一些便于存取基本类型的数据的方法。
将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap在job的执行过程中,可以从JobDataMap中取出数据

JobBuilder

用于定义/构建 JobDetail 实例,用于定义作业的实例。

JobBuilder的构造器是protected修饰的,对外暴露的newJob()方法,使用build() 做返回值构建。

public class JobBuilder {
private JobKey key;
private String description;
private Class<? extends Job> jobClass;
private boolean durability;
private boolean shouldRecover;
private JobDataMap jobDataMap = new JobDataMap();

protected JobBuilder() {
}

public static JobBuilder newJob() {
return new JobBuilder();
}

public static JobBuilder newJob(Class<? extends Job> jobClass) {
JobBuilder b = new JobBuilder();
b.ofType(jobClass);
return b;
}

public JobDetail build() {
JobDetailImpl job = new JobDetailImpl();
job.setJobClass(this.jobClass);
job.setDescription(this.description);
if (this.key == null) {
this.key = new JobKey(Key.createUniqueName((String)null), (String)null);
}

job.setKey(this.key);
job.setDurability(this.durability);
job.setRequestsRecovery(this.shouldRecover);
if (!this.jobDataMap.isEmpty()) {
job.setJobDataMap(this.jobDataMap);
}

return job;
}
}

Trigger

定义执行给定作业的计划的组件,给定时任务附带执行属性,做哪些动作,都是由Trigger提供的。

public interface Trigger extends Serializable, Cloneable, Comparable<Trigger> {
long serialVersionUID = -3904243490805975570L;
int MISFIRE_INSTRUCTION_SMART_POLICY = 0;
int MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1;
int DEFAULT_PRIORITY = 5;

TriggerKey getKey();

JobKey getJobKey();

String getDescription();

String getCalendarName();

JobDataMap getJobDataMap();

int getPriority();

boolean mayFireAgain();

Date getStartTime();

Date getEndTime();

Date getNextFireTime();

Date getPreviousFireTime();

Date getFireTimeAfter(Date var1);

Date getFinalFireTime();

int getMisfireInstruction();

TriggerBuilder<? extends Trigger> getTriggerBuilder();

ScheduleBuilder<? extends Trigger> getScheduleBuilder();

boolean equals(Object var1);

int compareTo(Trigger var1);

public static class TriggerTimeComparator implements Comparator<Trigger>, Serializable {
private static final long serialVersionUID = -3904243490805975570L;

public TriggerTimeComparator() {
}

public static int compare(Date nextFireTime1, int priority1, TriggerKey key1, Date nextFireTime2, int priority2, TriggerKey key2) {
if (nextFireTime1 != null || nextFireTime2 != null) {
if (nextFireTime1 == null) {
return 1;
}

if (nextFireTime2 == null) {
return -1;
}

if (nextFireTime1.before(nextFireTime2)) {
return -1;
}

if (nextFireTime1.after(nextFireTime2)) {
return 1;
}
}

int comp = priority2 - priority1;
return comp != 0 ? comp : key1.compareTo(key2);
}

public int compare(Trigger t1, Trigger t2) {
return compare(t1.getNextFireTime(), t1.getPriority(), t1.getKey(), t2.getNextFireTime(), t2.getPriority(), t2.getKey());
}
}

public static enum CompletedExecutionInstruction {
NOOP,
RE_EXECUTE_JOB,
SET_TRIGGER_COMPLETE,
DELETE_TRIGGER,
SET_ALL_JOB_TRIGGERS_COMPLETE,
SET_TRIGGER_ERROR,
SET_ALL_JOB_TRIGGERS_ERROR;

private CompletedExecutionInstruction() {
}
}

public static enum TriggerState {
NONE,
NORMAL,
PAUSED,
COMPLETE,
ERROR,
BLOCKED;

private TriggerState() {
}
}
}

主要属性

TriggerKey

new TriggerKey(this.getName(), this.getGroup());

JobKey

public JobKey getJobKey() {
return this.getJobName() == null ? null : new JobKey(this.getJobName(), this.getJobGroup());
}

AbstractTrigger

Trigger集成与于AbstractTrigger类,AbstractTrigger提供基础信息

public abstract class AbstractTrigger<T extends Trigger> implements OperableTrigger {
private static final long serialVersionUID = -3904243490805975570L;
private String name;
private String group = "DEFAULT";
private String jobName;
private String jobGroup = "DEFAULT";
private String description;
private JobDataMap jobDataMap;
private boolean volatility = false;
private String calendarName = null;
private String fireInstanceId = null;
private int misfireInstruction = 0;
private int priority = 5;
private transient TriggerKey key = null;
}

常用集成类

SimpleTrigger

SimpleTrigger可以满足的调度需求是:在具体的时间点执行一次,或者在具体的时间点执行,并且以指定的间隔重复执行若干次。比如,你有一个trigger,你可以设置它在2015年1月13日的上午11:23:54准时触发,或者在这个时间点触发,并且每隔2秒触发一次,一共重复5次。

public interface SimpleTrigger extends Trigger {
long serialVersionUID = -3735980074222850397L;
int MISFIRE_INSTRUCTION_FIRE_NOW = 1;
int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2;
int MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3;
int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4;
int MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5;
int REPEAT_INDEFINITELY = -1;

int getRepeatCount();

long getRepeatInterval();

int getTimesTriggered();

TriggerBuilder<SimpleTrigger> getTriggerBuilder();
}

CronTrigger

CronTrigger通常比SimpleTrigger更有用,如果您需要基于日历的概念而不是按照SimpleTrigger的精确指定间隔进行重新启动的作业启动计划。

使用CronTrigger,您可以指定号时间表,例如“每周五中午”或“每个工作日和上午9:30”,甚至“每周一至周五上午9:00至10点之间每5分钟”和1月份的星期五“。

public interface CronTrigger extends Trigger {
long serialVersionUID = -8644953146451592766L;
int MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1;
int MISFIRE_INSTRUCTION_DO_NOTHING = 2;

String getCronExpression();

TimeZone getTimeZone();

String getExpressionSummary();

TriggerBuilder<CronTrigger> getTriggerBuilder();
}

实际项目应用

1.下面是实际项目应用创建一个定时任务的代码:

/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, SysJobEntity job) throws SchedulerException, TaskException {
Class<? extends Job> jobClass = getQuartzJobClass(job);
// 构建job信息
Long id = job.getId();
String jobGroup = job.getJobGroup();
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(id, jobGroup)).build();

// 表达式调度构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);

// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(id, jobGroup))
.withSchedule(cronScheduleBuilder).build();

// 放入参数,运行时的方法可以获取
jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

// 判断是否存在
if (scheduler.checkExists(getJobKey(id, jobGroup))) {
// 防止创建时存在数据问题 先移除,然后在执行创建操作
scheduler.deleteJob(getJobKey(id, jobGroup));
}

scheduler.scheduleJob(jobDetail, trigger);

// 暂停任务
if (job.getStatus()==ScheduleConstants.STATUS_PAUSE) {
scheduler.pauseJob(ScheduleUtils.getJobKey(id, jobGroup));
}
}

  1. 使用Scheduler类通过@Resource注解注入,下方是源码接口内容,非常好用,基本都已经封装好,直接用就可以了。

package org.quartz;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.quartz.Trigger.TriggerState;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.spi.JobFactory;

public interface Scheduler {
String DEFAULT_GROUP = "DEFAULT";
String DEFAULT_RECOVERY_GROUP = "RECOVERING_JOBS";
String DEFAULT_FAIL_OVER_GROUP = "FAILED_OVER_JOBS";
String FAILED_JOB_ORIGINAL_TRIGGER_NAME = "QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME";
String FAILED_JOB_ORIGINAL_TRIGGER_GROUP = "QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP";
String FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING";
String FAILED_JOB_ORIGINAL_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_SCHEDULED_FIRETIME_IN_MILLISECONDS_AS_STRING";

String getSchedulerName() throws SchedulerException;

String getSchedulerInstanceId() throws SchedulerException;

SchedulerContext getContext() throws SchedulerException;

void start() throws SchedulerException;

void startDelayed(int var1) throws SchedulerException;

boolean isStarted() throws SchedulerException;

void standby() throws SchedulerException;

boolean isInStandbyMode() throws SchedulerException;

void shutdown() throws SchedulerException;

void shutdown(boolean var1) throws SchedulerException;

boolean isShutdown() throws SchedulerException;

SchedulerMetaData getMetaData() throws SchedulerException;

List<JobExecutionContext> getCurrentlyExecutingJobs() throws SchedulerException;

void setJobFactory(JobFactory var1) throws SchedulerException;

ListenerManager getListenerManager() throws SchedulerException;

Date scheduleJob(JobDetail var1, Trigger var2) throws SchedulerException;

Date scheduleJob(Trigger var1) throws SchedulerException;

void scheduleJobs(Map<JobDetail, Set<? extends Trigger>> var1, boolean var2) throws SchedulerException;

void scheduleJob(JobDetail var1, Set<? extends Trigger> var2, boolean var3) throws SchedulerException;

boolean unscheduleJob(TriggerKey var1) throws SchedulerException;

boolean unscheduleJobs(List<TriggerKey> var1) throws SchedulerException;

Date rescheduleJob(TriggerKey var1, Trigger var2) throws SchedulerException;

void addJob(JobDetail var1, boolean var2) throws SchedulerException;

void addJob(JobDetail var1, boolean var2, boolean var3) throws SchedulerException;

boolean deleteJob(JobKey var1) throws SchedulerException;

boolean deleteJobs(List<JobKey> var1) throws SchedulerException;

void triggerJob(JobKey var1) throws SchedulerException;

void triggerJob(JobKey var1, JobDataMap var2) throws SchedulerException;

void pauseJob(JobKey var1) throws SchedulerException;

void pauseJobs(GroupMatcher<JobKey> var1) throws SchedulerException;

void pauseTrigger(TriggerKey var1) throws SchedulerException;

void pauseTriggers(GroupMatcher<TriggerKey> var1) throws SchedulerException;

void resumeJob(JobKey var1) throws SchedulerException;

void resumeJobs(GroupMatcher<JobKey> var1) throws SchedulerException;

void resumeTrigger(TriggerKey var1) throws SchedulerException;

void resumeTriggers(GroupMatcher<TriggerKey> var1) throws SchedulerException;

void pauseAll() throws SchedulerException;

void resumeAll() throws SchedulerException;

List<String> getJobGroupNames() throws SchedulerException;

Set<JobKey> getJobKeys(GroupMatcher<JobKey> var1) throws SchedulerException;

List<? extends Trigger> getTriggersOfJob(JobKey var1) throws SchedulerException;

List<String> getTriggerGroupNames() throws SchedulerException;

Set<TriggerKey> getTriggerKeys(GroupMatcher<TriggerKey> var1) throws SchedulerException;

Set<String> getPausedTriggerGroups() throws SchedulerException;

JobDetail getJobDetail(JobKey var1) throws SchedulerException;

Trigger getTrigger(TriggerKey var1) throws SchedulerException;

TriggerState getTriggerState(TriggerKey var1) throws SchedulerException;

void resetTriggerFromErrorState(TriggerKey var1) throws SchedulerException;

void addCalendar(String var1, Calendar var2, boolean var3, boolean var4) throws SchedulerException;

boolean deleteCalendar(String var1) throws SchedulerException;

Calendar getCalendar(String var1) throws SchedulerException;

List<String> getCalendarNames() throws SchedulerException;

boolean interrupt(JobKey var1) throws UnableToInterruptJobException;

boolean interrupt(String var1) throws UnableToInterruptJobException;

boolean checkExists(JobKey var1) throws SchedulerException;

boolean checkExists(TriggerKey var1) throws SchedulerException;

void clear() throws SchedulerException;
}


举报

相关推荐

0 条评论