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                    : 任務全部執行完成

通過以上日志,可以看到注冊了全局監聽器后,會監聽所有任務的事件

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM