Spring 3整合Quartz 2实现定时任务三:动态暂停 恢复 修改和删除任务

分类: Spring 58人评论 selfly 1年前发布

前面我们已经完成了spring 3和quartz 2的整合以及动态添加定时任务,我们接着来完善它,使之能支持更多的操作,例如暂停、恢复、修改等。

在动态添加定时任务中其实已经涉及到了其中的一些代码,这里我们再来细化的理一理。先来看一下我们初步要实现的目标效果图,这里我们只在内存中操作,并没有把quartz的任何信息保存到数据库,即使用的是RAMJobStore,当然如果你有需要,可以实现成JDBCJobStore,那样任务信息将会更全面,貌似还有专门的监控工具,不过本人没有用过:

如上图,我们要先列出计划中的定时任务以及正在执行中的定时任务,这里的正在执行中指的是任务已经触发线程还没执行完的情况。比如每天2点执行一个数据导入操作,这个操作执行时间需要5分钟,在这5分钟之内这个任务才是运行中的任务。当任务正常时可以使用暂停按钮,任务暂停时可以使用恢复按钮。

trigger各状态说明:

None:Trigger已经完成,且不会在执行,或者找不到该触发器,或者Trigger已经被删除 NORMAL:正常状态 PAUSED:暂停状态 COMPLETE:触发器完成,但是任务可能还正在执行中 BLOCKED:线程阻塞状态 ERROR:出现错误

计划中的任务

指那些已经添加到quartz调度器的任务,因为quartz并没有直接提供这样的查询接口,所以我们需要结合JobKey和Trigger来实现,核心代码:

Scheduler scheduler = schedulerFactoryBean.getScheduler();
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
for (JobKey jobKey : jobKeys) {
    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
    for (Trigger trigger : triggers) {
        ScheduleJob job = new ScheduleJob();
        job.setJobName(jobKey.getName());
        job.setJobGroup(jobKey.getGroup());
        job.setDesc("触发器:" + trigger.getKey());
        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
        job.setJobStatus(triggerState.name());
        if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;
            String cronExpression = cronTrigger.getCronExpression();
            job.setCronExpression(cronExpression);
        }
        jobList.add(job);
    }
}

上面代码中的jobList就是我们需要的计划中的任务列表,需要注意一个job可能会有多个trigger的情况,在下面讲到的立即运行一次任务的时候,会生成一个临时的trigger也会出现在这。这里把一个Job有多个trigger的情况看成是多个任务。我们前面包括在实际项目中一般用到的都是CronTrigger ,所以这里我们着重处理了下CronTrigger的情况。

运行中的任务

实现和计划中的任务类似,核心代码:

Scheduler scheduler = schedulerFactoryBean.getScheduler();
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(executingJobs.size());
for (JobExecutionContext executingJob : executingJobs) {
    ScheduleJob job = new ScheduleJob();
    JobDetail jobDetail = executingJob.getJobDetail();
    JobKey jobKey = jobDetail.getKey();
    Trigger trigger = executingJob.getTrigger();
    job.setJobName(jobKey.getName());
    job.setJobGroup(jobKey.getGroup());
    job.setDesc("触发器:" + trigger.getKey());
    Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
    job.setJobStatus(triggerState.name());
    if (trigger instanceof CronTrigger) {
        CronTrigger cronTrigger = (CronTrigger) trigger;
        String cronExpression = cronTrigger.getCronExpression();
        job.setCronExpression(cronExpression);
    }
    jobList.add(job);
}
暂停任务

这个比较简单,核心代码:

Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.pauseJob(jobKey);
恢复任务

和暂停任务相对,核心代码:

Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.resumeJob(jobKey);
删除任务

删除任务后,所对应的trigger也将被删除

Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.deleteJob(jobKey);
立即运行任务

这里的立即运行,只会运行一次,方便测试时用。quartz是通过临时生成一个trigger的方式来实现的,这个trigger将在本次任务运行完成之后自动删除。trigger的key是随机生成的,例如:DEFAULT.MT_4k9fd10jcn9mg。在我的测试中,前面的DEFAULT.MT是固定的,后面部分才随机生成。

Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.triggerJob(jobKey);
更新任务的时间表达式

更新之后,任务将立即按新的时间表达式执行:

Scheduler scheduler = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(),
    scheduleJob.getJobGroup());
//获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob
    .getCronExpression());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
    .withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);

到这里,我们的spring3 整合quartz 2的定时任务功能终于是告一段落了,对常用的一些功能进行了实现,相信可以满足一般项目的需求了。

上一篇:
下一篇:

你可能感兴趣的文章

58 条评论
ceoajun · 5月前

学习了

回复

selfly 作者 · 1年前

@知了 发现层级太多不能直接回复了,应该是你spring配置中注入的对象弄错了

回复

0
schedulerFactoryBean 从spring创建注入的时候应该怎么写呢? 单纯初始化 private static SchedulerFactoryBean schedulerFactoryBean; 就可以了吗?为什么我一直都报NullPointerException错误呢? 不管怎么取 schedulerFactoryBean都是null。请指点一下
diutrue · 1年前
tonghai8023 · 1年前
能留个QQ么?280995594,还有点地方没弄明白

回复

Jerome · 1年前
非常感谢分享,我实验了一下,没问题

回复

0
可以请教下么?QQ:280995594
tonghai8023 · 1年前
0
你好!发一下demo好吗?谢谢了。QQ1054185474
clshanghe · 1年前
selfly 作者 · 1年前

不错,有兴趣交换友链不

回复

0
想请教一下,在动态生成的任务执行类(即继承Job类的那个类)里,因为业务需求,想要用到spring的sessionFactory,或者一些dao的接口,但是如果直接通过@Autowired注解的方法无论如何取到的都是null,想问一下对于这种情况,有好的解决办法吗?谢谢!
diutrue · 1年前
Rebel · 1年前
我的qq79674057,有的问题想请教下,就是我的计划现在已经进行了注册并且开始了执行,但是我用pauseJob这个方法进行暂停,发现并没有实现将这个计划暂停,还是执行了此次计划,不知道哪里错了,求教!

回复

0

检查一下你的jobName和jobGroup

selfly 作者 · 1年前
leehow1988 · 1年前
感谢楼主,配置成功了 :smile:

回复

0
你好!你是怎么配置的,可以请教一下吗? 我的QQ1054185474
clshanghe · 1年前
0
634623907 请教
634623907 · 1年前
zjlwm · 1年前
感谢楼主啦,困扰我多久的quartz动态添加任务,终于找到解决方法了,感谢阿

回复

0
求demo,谢谢,610966664@qq.com
610966664 · 1年前
wintely · 1年前
可以发个demo吗 ?手上的项目刚好遇到这样的需求 307837369

回复

634623907 · 1年前
看了你的文章有不明白的地方,还想进一步请教qq:634623907

回复

0
你好!发个demo好吗!谢谢了!1054185474QQ
clshanghe · 1年前
dbac · 1年前
/** 计划任务map */ private static Map jobMap = new HashMap(); static { for (int i = 0; i < 5; i++) { ScheduleJob job = new ScheduleJob(); job.setJobId("10001" + i); job.setJobName("data_import" + i); job.setJobGroup("dataWork"); job.setJobStatus("1"); job.setCronExpression("0/5 * * * * ?"); job.setDesc("数据导入任务"); addJob(job); } } /** * 添加任务 * @param scheduleJob */ public static void addJob(ScheduleJob scheduleJob) { jobMap.put(scheduleJob.getJobGroup() + "_" + scheduleJob.getJobName(), scheduleJob); } 这段话 貌似没有任何含义 DataWorkContext 这个类能提供看下?

回复

0
这个类只是我的demo中制造测试数据用的,实际应用中确实没有意义,应该保存在数据库或其它地方 /** * 上下文的一些参数信息 *

* User: liyd * Date: 13-12-20 * Time: 下午2:47 */ public final class DataWorkContext { /** * 计划任务map */ private static Map jobMap = new HashMap(); static { ScheduleJob job = new ScheduleJob(); job.setJobId("10001"); job.setJobName("contentPullConversionTask"); job.setJobGroup("dataWork"); job.setJobStatus("1"); job.setCronExpression("0 0 2 * * ?"); job.setDesc("数据导入任务"); addJob(job); } /** * 添加任务 * * @param scheduleJob */ public static void addJob(ScheduleJob scheduleJob) { jobMap.put(scheduleJob.getJobGroup() + "_" + scheduleJob.getJobName(), scheduleJob); } /** * 获取任务 * * @param jobId * @return */ public static ScheduleJob getJob(String jobId) { return jobMap.get(jobId); } /** * 获取所有任务 * * @return */ public static List getAllJob() { List jobList = new ArrayList(jobMap.size()); for (Map.Entry entry : jobMap.entrySet()) { jobList.add(entry.getValue()); } return jobList; } }

selfly 作者 · 1年前
dbac · 1年前
有没有demo源码 你这个写的不清不楚

回复

0
源码在整个项目当中,单独的demo目前没有,核心的代码都已经列出来了,只要封装个方法就好
selfly 作者 · 1年前
0
你把每个代码块封装成一个方法,schedulerFactoryBean是由spring注入的,参数scheduleJob是实体类,基本上就实现功能了
selfly 作者 · 1年前
liuyongqian6666 · 1年前
学习了,谢谢分享

回复

moonglade008 · 1年前
RAMJobStore还是JDBCJobStore需要在哪里配置的?

回复

mrxiao · 1年前
学习中

回复

sumohen · 1年前
正好需要这一块 学习了

回复

zy2088 · 1年前
com.dexcoder.assistant 这个jar在哪啊 下不下来 楼主分享下.谢谢

回复

wjxyz0502 · 1年前
好东西

回复

tomsys · 1年前
学习了

回复

kel5723 · 1年前
com.dexcoder.assistant 这个jar在哪啊 下不下来 楼主分享下.谢谢

回复

载入中...