zoukankan      html  css  js  c++  java
  • Quartz任务监听器

    前言:

    在项目中,遇到这样的需求:在指定的时间范围内执行定时任务(会执行多次),当任务最后一次执行完后,通知调用方。

    在网上找了各种资料,都达不到想要的效果。自己研究了一下,将研究成果记录下来。

    在学习本篇之前,最好参考下上一篇:Quartz基本使用。涉及到Quartz的基本配置,本篇不作介绍

    监听器介绍:

    Quartz监听器用于当任务调度中,你所关注的事件发生变化时,能够及时获取这一事件的通知。

    Quartz监听器主要有JobListener、TriggerListener、SchedulerListener三种(后两种感觉用不上),分别表示任务、触发器、调度器对应的监听器。

    Quartz监听器分为全局监听器和非全局监听器,全局监听器可以接收所有的Job/Trigger的时间通知,而非全局监听器只能接受在其注册的Job/Trigger事件。

    上代码:

    1、在上篇的 MyQuartzScheduler 类中增加两个方法:

    /**
         * 注册任务监听器(全局监听器,监听所有任务)
         */
        @SneakyThrows
        public void addJobListener(JobListener listener) {
            scheduler.getListenerManager().addJobListener(listener);
        }
    
        /**
         * 为任务增加任务监听器
         */
        @SneakyThrows
        public void addJobListener(String name, Class<? extends Job> jobClass, JobListener listener) {
            name = StringUtils.join(JOB_NAME_PREFIX, name);
            String group = jobClass.getSimpleName();
            JobKey jobKey = new JobKey(name, group);
            Matcher<JobKey> matcher = KeyMatcher.keyEquals(jobKey);
            scheduler.getListenerManager().addJobListener(listener, matcher);
        }

    2、创建一个任务监听器:

    @Slf4j
    public class MyJobListener extends JobListenerSupport {
    
        private MyQuartzScheduler quartzScheduler;
        private String jobName;
    
        public MyJobListener() {
        }
    
        public MyJobListener(MyQuartzScheduler quartzScheduler) {
            this.quartzScheduler = quartzScheduler;
        }
    
        public MyJobListener(MyQuartzScheduler quartzScheduler, String jobName) {
            this.quartzScheduler = quartzScheduler;
            this.jobName = jobName;
        }
    
        @Override
        public String getName() {
            /**
             * 一定得返回一个值(如果需要同时监听多个任务,这里的name必须与任务名称一致,否则只会监听一个任务)
             */
            if (StringUtils.isNotEmpty(jobName)) {
                return jobName;
            }
            return "default";
        }
    
        /**
         * 任务单次执行完一次,就会回调该方法。也就是每一次任务执行完成,该监听器都会执行。不过,只有当最后一次执行时,任务的状态才是COMPLETE,其它时候都是NORMAL
         */
        @Override
        public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
            if (quartzScheduler != null) {
                TriggerKey triggerKey = context.getTrigger().getKey();
                TriggerState state = quartzScheduler.getJobState(triggerKey);
                log.info("name:{},group:{},state:{}", triggerKey.getName(), triggerKey.getGroup(), state);
                if (TriggerState.COMPLETE.equals(state)) {
                    log.info("任务全部执行完成");
                }
            }
        }
    
    }

    注意点:

    getName()方法:一定得返回一个值(如果将该监听器注册为非全局监听器,并且同时监听多个任务时,这里的name必须与任务名称一致,否则只会监听最近创建的一个任务)

    3、在上篇中 QuartzApiController 中增加如下方法:

      /**
         * 带定时表达式和指定时间范围的任务
         */
        @GetMapping("/job/cronInRange/{id}")
        public void cronQuartzJobInRange(@PathVariable String id) {
            Map<String, Object> params = new HashMap<>();
            params.put("id", id);
            // 每10秒执行一次
            quartzScheduler.addJobWithCron(MyJob.class, id, "0/10 * * * * ?", 30, params);
            // 增加任务监听
            quartzScheduler.addJobListener(id, MyJob.class, new MyJobListener(quartzScheduler, id));
        }

    4、启动服务测试:

    非全局监听器,请求:http://localhost:18091/quartz/job/cronInRange/123,可以看到如下日志信息:

    2020-12-11 22:36:13.323  INFO 13752 --- [io-18091-exec-1] c.x.q.MyQuartzScheduler                  : 创建任务,任务名称:JOB_123
    2020-12-11 22:36:20.072  INFO 13752 --- [ce_two_Worker-1] c.x.q.j.MyJob                            : 执行MyJob任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:36:20.075  INFO 13752 --- [ce_two_Worker-1] c.x.q.l.MyJobListener                    : name:123,group:MyJob,state:NORMAL
    2020-12-11 22:36:30.042  INFO 13752 --- [ce_two_Worker-2] c.x.q.j.MyJob                            : 执行MyJob任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:36:30.071  INFO 13752 --- [ce_two_Worker-2] c.x.q.l.MyJobListener                    : name:123,group:MyJob,state:NORMAL
    2020-12-11 22:36:40.041  INFO 13752 --- [ce_two_Worker-3] c.x.q.j.MyJob                            : 执行MyJob任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:36:40.045  INFO 13752 --- [ce_two_Worker-3] c.x.q.l.MyJobListener                    : name:123,group:MyJob,state:COMPLETE
    2020-12-11 22:36:40.046  INFO 13752 --- [ce_two_Worker-3] c.x.q.l.MyJobListener                    : 任务全部执行完成

    通过结果可以看到:每一次任务执行完成,该监听器都会执行。不过,只有当最后一次执行时,任务的状态才是COMPLETE,其它时候都是NORMAL

    当判断状态为 COMPLETE 时,通知调用方   ==> 以上代码就满足了最上面的需求

    接下来测试下全局监听器:

    1、创建一个Job任务MyJob2:

    @Slf4j
    public class MyJob2 extends QuartzJobBean {
    
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
            JobDetail jobDetail = context.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            JobDataMap dataMap = jobDetail.getJobDataMap(); // 接收参数
            log.info("执行MyJob2任务,任务名称:{},接收参数:{}", jobKey.getName(), dataMap.getString("id"));
        }
    
    }

    2、修改 QuartzApiController 类中的cronQuartzJobInRange方法,并增加 addJobListener 方法:

        /**
         * 带定时表达式和指定时间范围的任务
         */
        @GetMapping("/job/cronInRange/{id}")
        public void cronQuartzJobInRange(@PathVariable String id) {
            Map<String, Object> params = new HashMap<>();
            params.put("id", id);
            // 每10秒执行一次
            quartzScheduler.addJobWithCron(MyJob.class, id, "0/10 * * * * ?", 30, params);
            quartzScheduler.addJobWithCron(MyJob2.class, id, "0/10 * * * * ?", 30, params);
            // // 增加任务监听
            // quartzScheduler.addJobListener(id, MyJob.class, new
            // MyJobListener(quartzScheduler, id));
        }
    
        /**
         * 注册任务监听器(全局)
         */
        @GetMapping("/addJobListener")
        public void addJobListener() {
            quartzScheduler.addJobListener(new MyJobListener(quartzScheduler));
        }

    3、在请求 http://localhost:18091/quartz/job/cronInRange/123 后,立马请求 http://localhost:18091/quartz/addJobListener,可以看到如下日志:

    2020-12-11 22:57:51.442  INFO 1748 --- [io-18091-exec-1] c.x.q.MyQuartzScheduler                  : 创建任务,任务名称:JOB_123
    2020-12-11 22:57:51.501  INFO 1748 --- [io-18091-exec-1] c.x.q.MyQuartzScheduler                  : 创建任务,任务名称:JOB_123
    2020-12-11 22:58:00.078  INFO 1748 --- [ce_two_Worker-1] c.x.q.j.MyJob                            : 执行MyJob任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:58:00.087  INFO 1748 --- [ce_two_Worker-1] c.x.q.l.MyJobListener                    : name:123,group:MyJob,state:NORMAL
    2020-12-11 22:58:00.118  INFO 1748 --- [ce_two_Worker-2] c.x.q.j.MyJob2                           : 执行MyJob2任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:58:00.121  INFO 1748 --- [ce_two_Worker-2] c.x.q.l.MyJobListener                    : name:123,group:MyJob2,state:NORMAL
    2020-12-11 22:58:10.049  INFO 1748 --- [ce_two_Worker-3] c.x.q.j.MyJob                            : 执行MyJob任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:58:10.052  INFO 1748 --- [ce_two_Worker-3] c.x.q.l.MyJobListener                    : name:123,group:MyJob,state:NORMAL
    2020-12-11 22:58:10.095  INFO 1748 --- [ce_two_Worker-4] c.x.q.j.MyJob2                           : 执行MyJob2任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:58:10.100  INFO 1748 --- [ce_two_Worker-4] c.x.q.l.MyJobListener                    : name:123,group:MyJob2,state:NORMAL
    2020-12-11 22:58:20.034  INFO 1748 --- [ce_two_Worker-5] c.x.q.j.MyJob                            : 执行MyJob任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:58:20.037  INFO 1748 --- [ce_two_Worker-5] c.x.q.l.MyJobListener                    : name:123,group:MyJob,state:COMPLETE
    2020-12-11 22:58:20.039  INFO 1748 --- [ce_two_Worker-5] c.x.q.l.MyJobListener                    : 任务全部执行完成
    2020-12-11 22:58:20.076  INFO 1748 --- [ce_two_Worker-6] c.x.q.j.MyJob2                           : 执行MyJob2任务,任务名称:JOB_123,接收参数:123
    2020-12-11 22:58:20.079  INFO 1748 --- [ce_two_Worker-6] c.x.q.l.MyJobListener                    : name:123,group:MyJob2,state:COMPLETE
    2020-12-11 22:58:20.079  INFO 1748 --- [ce_two_Worker-6] c.x.q.l.MyJobListener                    : 任务全部执行完成

    通过以上日志,可以看到注册了全局监听器后,会监听所有任务的事件

  • 相关阅读:
    关于html5的一些知识。
    常见的http状态码总结。
    踩坑记录-安装node-sass运行报错TypeError: this.getResolve is not a function at Object.loader
    踩坑记录-!!vue-style-loader!css-loader错误
    koa-passport做登录注册验证
    nuxt项目里使用vuex状态树
    node(koa、nuxt等项目)中使用import报错问题
    koa+nodemailer实现邮箱验证注册功能
    踩坑记录-nuxt引入vuex报错store/index.js should export a method that returns a Vuex instance.
    常用shell命令积累
  • 原文地址:https://www.cnblogs.com/xuwenjin/p/14121063.html
Copyright © 2011-2022 走看看