一、需求说明
什么是动态任务调度?
在上一篇中,我们的Job,JobDetail,Trigger都是硬编码,写死在代码里的
这样不符合实际应用。
实现通过接口来创建、暂停、重启、删除、修改任务等操作。
二、实现动态调度
动态调度的相关功能,都是集中在Scheduler组件中。
1、开发步骤
- 自定义Job类
- 自定义任务Bean
JobBean的作用,是为了,封装所有Job的公共特点,方便后续的Scheduler操作
public class JobBean {
private String jobName;
private String jobClass;
private String cron;}
- 编写操作所有Job的工具类
JobUtils
这里主要演示6个常用操作
那么,具体的方法内部实现逻辑是,和上一篇顺序一样,JobDetail,Trigger(其中包含cron)
然后,关联到Scheduler中。
import com.pzj.quartz.entity.JobBean;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
public class JobUtils {
public static void createJob(Scheduler scheduler, JobBean jobBean){
Class<? extends Job> jobClass = null;
JobDetail jobDetail = null;
Trigger trigger = null;
try {
jobClass = (Class<? extends Job>) Class.forName(jobBean.getJobClass());
jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobBean.getJobName()) //唯一标识
.storeDurably() //持久化
.usingJobData("count",1) // 共享数据初始化
.build();
trigger = TriggerBuilder.newTrigger()
.withIdentity(jobBean.getJobName()+"_trigger") //设置唯一标识
.forJob(jobDetail) //关联创建的JobDetail
.withSchedule(CronScheduleBuilder.cronSchedule(jobBean.getCron())) //设置cron
.build();
scheduler.scheduleJob(jobDetail,trigger);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
public static void pauseJob(Scheduler scheduler,String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
public static void resumeJob(Scheduler scheduler,String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
public static void deleteJob(Scheduler scheduler,String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.deleteJob(jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
public static void runOnceJob(Scheduler scheduler,String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.triggerJob(jobKey);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
/**
* 本案例中,只是实现了cron的修改
* 另外一种实现思路就是,先删除旧的任务,在创建新任务。
* 实现对job的整体修改。
* @param scheduler
* @param jobBean
*/
public static void modifyJob(Scheduler scheduler,JobBean jobBean){
//获取任务触发器的唯一标识
TriggerKey triggerKey = TriggerKey.triggerKey(jobBean.getJobName() + "_trigger");
//通过唯一标识获取旧的触发器对象
try {
CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//使用新cron表达式构建新的触发器
String newCron = jobBean.getCron();
CronTrigger newTriger = oldTrigger.getTriggerBuilder()
.withSchedule(CronScheduleBuilder.cronSchedule(newCron))
.build();
//调度器更新任务的触发器
scheduler.rescheduleJob(triggerKey,newTriger);
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
}
然后,在controller接口中,分别调用util的具体方法即可。
这里要注意,每一个功能的测试,是简历在线创建了job任务的基础上进行的。
那么,到此,就实现了动态操作任务调度的效果。
2、出现的问题
在测试修改调度任务的时候,会出现一个问题
任务创建时,cron是2秒一次
修改成5秒一次。
会发现,18,19,20连续三秒都执行了一次。

问题描述:
这个问题,专业术语叫:misfire
当调度器执行 rescheduleJob(triggerKey,trigger)去更新某个triggerKey对应的新trigger时,会导致新trigger相关联的定时任务立即执行一次(暂停任务亦如此)。
解决办法:
就是在创建Job任务的时候,为CronScheduleBuilder设置MisfirePolicy即可。
/**
* 设置定时任务策略
*/
public static CronScheduleBuilder handleCronScheduleMisfirePolicy(JobBean job, CronScheduleBuilder cb)
throws TaskException
{
switch (job.getMisfirePolicy())
{
case ScheduleConstants.MISFIRE_DEFAULT:
return cb;
case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
return cb.withMisfireHandlingInstructionIgnoreMisfires();
case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
return cb.withMisfireHandlingInstructionFireAndProceed();
case ScheduleConstants.MISFIRE_DO_NOTHING:
return cb.withMisfireHandlingInstructionDoNothing();
default:
throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
+ "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
}
}
三、总结
这种quartz框架的实现,就比较符合实际应用场景了。
可以通过接口去操作Job,这样更加的灵活。
但是,这里还没有实现数据库保存Job配置信息的功能,后面继续优化。
开发思路:
这种实现方式,不是通过config配置类来注入。
是通过new对象,创建所需组件。
依然是,Job,JobDetail,Trigger,Scheduler的顺序,依次创建并绑定。

3577

被折叠的 条评论
为什么被折叠?



