SpringBoot下,使用集群配置Quartz链接:
定时任务调度框架Quartz–SpringBoot使用Quartz并使用集群配置
创建一个任务非常简单,就是根据JOB接口实现类生成一个CronTrigger或者SImpleTrigger,并同时创建一个JobDetail,交给Scheduler调度器即可。具体实现代码完全可以参照CronTrgger与SimpleTrigger
第一种方案
这里需要注意的是,在创建JobDetail的时候,可以增加一个Boolean属性storeDurably
,true表明是否该JobDetail在没有任何Trigger与之关联的时候,还存放在数据库中。
JobDetail jobDetail = newJob(clazz)
.withIdentity(param.getName(), param.getGroup())
.withDescription(param.getDescription())
.usingJobData(new JobDataMap())
//没有Trigger与之相关联也会存放在数据库中
.storeDurably()
.build();
//入库,方便下一步Trigger与该JobDetail绑定
scheduler.addJob(jobDetail, false);
//创建CronTrigger,失火策略使用错过不处理
Trigger cronTrigger = newTrigger()
.withIdentity(param.getName(), param.getGroup())
.withSchedule(
cronSchedule(param.getCron())
.withMisfireHandlingInstructionDoNothing()
)
.withDescription(param.getDescription())
.forJob(jobDetail)
.build();
scheduler.scheduleJob(cronTrigger);
第二种方案
分别创建CronTriger与JobDetail。然后一次性交给schedule调度器加入调度进程。如果此时在调用一次scheduler.scheduleJob(job,otherTrigger),则会报错。因为Job已经加入到了Schedule调度中,不能重复加入。
@Autowird
private SchedulerFactoryBean schedulerFactoryBean;
public boolean addDynamicScheduleJob(JobParam param) {
try {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = new TriggerKey(param.getName(), param.getGroup());
if (scheduler.getTrigger(triggerKey) == null) {
//实现了Job接口的类
Class clazz = org.apache.commons.lang3.ClassUtils.getClass(param.getClassName());
if (Job.class.isAssignableFrom(clazz)) {
//创建CronTrigger,失火策略使用错过不处理
Trigger cronTrigger = newTrigger()
.withIdentity(param.getName(), param.getGroup())
.withSchedule(
cronSchedule(param.getCron())
.withMisfireHandlingInstructionDoNothing()
)
.withDescription(param.getDescription())
.build();
//通过Job实现类创建JobDetail
JobDetail jobDetail = newJob(clazz)
.withIdentity(param.getName(), param.getGroup())
.withDescription(param.getDescription())
.usingJobData(new JobDataMap())
.build();
scheduler.scheduleJob(jobDetail, cronTrigger);
return Boolean.TRUE;
} else {
throw new IllegalArgumentException("class类必须实现Job接口");
}
}
} catch (Exception e) {
LOGGER.error("an exception was occurred , caused by :{}", e.getMessage());
}
return Boolean.FALSE;
}
@Data
public class JobParam {
private String name;
private String cron;
private String group;
private String className;
private String description;
}
其实从作者的注释上来看,如果直接删除Job,那么与之关联的所有Trigger会连带删除。
public interface Scheduler ...
/**
* Delete the identified Job
from the Scheduler - and any
* associated Trigger
s.
*
* @return true if the Job was found and deleted.
* @throws SchedulerException
* if there is an internal Scheduler error.
*/
boolean deleteJob(JobKey jobKey)
throws SchedulerException;
另外一个删除方法是删除Trigger,如果此Trigger关联到的Job没有其他Trigger,那么Job也会被删除。
public interface Scheduler ...
/**
* Remove the indicated {@link Trigger}
from the scheduler.
*
* If the related job does not have any other triggers, and the job is
* not durable, then the job will also be deleted.
*/
boolean unscheduleJob(TriggerKey triggerKey)
throws SchedulerException;
一般会按照下方的代码来删除Job与Trigger。先把Trigger暂停。并停止Trigger的调度。最后删除Job。Trigger与Job 一对多,所以先删除Trigger,再删除Job
public void deleteScheduleByNameAndGroup(String name, String group) {
try {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(name, group);
Trigger trigger = scheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
JobKey jobKey = JobKey.jobKey(name, group);
//暂停并不调度触发器
scheduler.pauseTrigger(triggerKey);
scheduler.unscheduleJob(triggerKey);
//删除任务
scheduler.deleteJob(jobKey);
} catch (Exception e) {
LOGGER.error("an exception was occurred , caused by :{}", e.getMessage());
throw new ScheduleRuntimeException(e);
}
}
修改一个任务很简单,就是通过JobKey删除以前的Trigger。然后再创建一个新的任务
1)通过TriggerKey暂停Trigger调度
2)通过TriggerKey删除Trigger
3)通过JobKey删除JobDetail
4)最后创建新的定时任务,代码参考创建定时任务。创建Trigger与JobDetail交给Scheduler
@SneakyThrows
public boolean reloadSchedule(JobParam job) {
//原来的的Job标识
JobKey jobKey = JobKey.jobKey(job.getSourceName(), job.getSourceGroup());
//新得Job标识
TriggerKey triggerKey = TriggerKey.triggerKey(job.getSourceName(), job.getSourceGroup());
//删除原来的Trigger
Scheduler scheduler = schedulerFactoryBean.getScheduler();
Trigger trigger = scheduler.getTrigger(triggerKey);
if (trigger != null) {
scheduler.pauseTrigger(triggerKey);
scheduler.unscheduleJob(triggerKey);
scheduler.deleteJob(jobKey);
}
return this.addDynamicScheduleJob(job);
}
暂停一个定时任务很简单,只需要知道这个任务的name与group即可。从作者的注释来看,让一个JobDetail暂停执行,实际上的实现方式就是让该JobDetail关联的所有Trigger的运行状态改为暂停。
public interface Scheduler ...
/**
* Pause the {@link org.quartz.JobDetail}
with the given
* key - by pausing all of its current Trigger
s.
*
* @see #resumeJob(JobKey)
*/
void pauseJob(JobKey jobKey)
throws SchedulerException;
我把测试的两个Trigger关联了同一个JobDetail,然后调用上述的Scheduler.pauseJob(Jobkey)方法,在QRTZ_TRIGGER
表中发现TRIGGER_STATE
的状态已经修改为PASUED
同样得,恢复一个JobDetail也有两种操作:唤醒Trigger与唤醒JobDetail
。
下面是通过JobKey恢复任务的源代码。通过JobKey唤醒此JobDetail关联的所有Trigger,并且触发Trigger们的失火策略。
public interface Scheduler ...
/**
* Resume (un-pause) the {@link org.quartz.JobDetail}
with
* the given key.
*
*
* If any of the Job
'sTrigger
s missed one
* or more fire-times, then the Trigger
's misfire
* instruction will be applied.
*
*
* @see #pauseJob(JobKey)
*/
void resumeJob(JobKey jobKey)
throws SchedulerException;
下面是通过TriggerKey恢复任务的源代码。通过TriggerKey唤醒此Trigger,从而让该Trigger开始调度它所关联的JobDetail,同时触发该Trigge的r失火策略。
public interface Scheduler ...
/**
* Resume (un-pause) the {@link Trigger}
with the given
* key.
*
*
* If the Trigger
missed one or more fire-times, then the
* Trigger
's misfire instruction will be applied.
*
*
* @see #pauseTrigger(TriggerKey)
*/
void resumeTrigger(TriggerKey triggerKey)
throws SchedulerException;
立即执行一个任务。从源代码上来看,它创建了一个临时的新的Trigger来安排这次执行任务
。不会影响到已经创建并存放在数据库中的Trigger。
public interface Scheduler ...
/**
* Trigger the identified {@link org.quartz.JobDetail}
* (execute it now).
*/
void triggerJob(JobKey jobKey)
throws SchedulerException;