Quartz-JobListener解读

简介: Quartz-JobListener解读

20191223202217702.png


概述


在某个所关注事件发生时,监听器提供了一种方便且非侵入性的机制来获得这一通知。Quartz 提供了三种类型的监听器:监听 Job 的,监听 Trigger 的,和监听 Scheduler 自已的。


本博文阐述如何应用每一种类型来更好的管理你的 Quartz 应用,并获悉到什么事件正在发生。


参考官方Demo:

http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/tutorial-lesson-07.html


步骤简述


要创建一个Listener, 只需要创建一个实现了org.quartz.TriggerListener或org.quartz.JobListener接口的对象即可。


在运行的时候,将Listeners注册进scheduler, 而且必须给一个name(可以通过他们的getName()方法获取Listener的name)。


除了继承接口,类也可以继承JobListenerSupport或TriggerListenerSupport,重写你感兴趣的event。


Listener通过scheduler的ListenerManager来注册,其中的Matcher 里描述哪个Jobs、Triggers需要被监听。


注意:

LListeners在运行的时候被注册进scheduler, 而不是保存在JobStore。Listener是和你的应用集成在一起的,这样每次你的应用运行的时候,都会在scheduler中重新注册listeners


全局/非全局监听器


JobListener 和 TriggerListener 可被注册为全局或非全局监听器。

  • 全局监听器能接收到所有的 Job/Trigger 的事件通知。
  • 非全局监听器(或者说是一个标准的监听器) 只能接收到那些在其上已注册了监听器的 Job 或 Triiger 的事件。


你要注册你的监听器为全局或非全局的需依据你特定的应用需要。


全局监听器是主动意识的,它们为了执行它们的任务而热切的去寻找每一个可能的事件。通常全局监听器要做的工作不用指定到特定的 Job 或 Trigger。非全局监听器一般是被动意识的,它们在所关注的 Trigger 激发之前或是 Job 执行之前什么事也不做。因此,非全局的监听器比起全局监听器而言更适合于修改或增加 Job 执行的工作。这有点像知名的装饰设计模式的装饰器。


全局 监听器


scheduler.addGlobalTriggerListener(new SimpleMyTriggerListener());


非全局监听器

scheduler.addTriggerListener( triggerListener );
trigger.addTriggerListener( triggerListener.getName() );


JobListener 任务监听器 示例


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcxMTE3MDU0NDQ3OTE4.png


JobListener源码


我们先来看下JobListener的源码:


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcxMTE3MDU1MjQwODA5.png


getName() :返回一个字符串用以说明 JobListener 的名称。对于注册为全局的监听器,getName()主要用于记录日志,对于由特定 Job 引用的JobListener,注册在 JobDetail 上的监听器名称必须匹配从监听器getName() 方法的返回值。


jobToBeExecuted() :Scheduler 在 JobDetail 将要被执行时调用这个方法。


jobExecutionVetoed() :Scheduler 在 JobDetail 即将被执行,但又被 TriggerListener否决了时调用这个方法。


jobWasExecuted() :Scheduler 在 JobDetail 被执行之后调用这个方法。


自定义监听器

import org.quartz.*;
public class MyJobListener implements JobListener {
    @Override
    public String getName() {
        return "MyJobListener";
    }
    @Override
    public void jobExecutionVetoed(JobExecutionContext arg0) {
        System.out.println("Job监听器:MyJobListener.jobExecutionVetoed()");
    }
    @Override
    public void jobToBeExecuted(JobExecutionContext arg0) {
        System.out.println("Job监听器:MyJobListener.jobToBeExecuted()");
    }
    @Override
    public void jobWasExecuted(JobExecutionContext arg0,
                               JobExecutionException arg1) {
        System.out.println("Job监听器:MyJobListener.jobWasExecuted()");
    }
}


注册监听器

MyJobListener myJobListener=new MyJobListener(); 
// 添加一个特定的job
scheduler.getListenerManager().addJobListener(myJobListener, KeyMatcher.jobKeyEquals(new JobKey("myJobName", "myJobGroup")));


上面的代码就可以变成:

scheduler.getListenerManager().addJobListener(myJobListener, jobKeyEquals(jobKey("myJobName", "myJobGroup")));
// 添加特定组的所有jobs
scheduler.getListenerManager().addJobListener(myJobListener, jobGroupEquals("myJobGroup"));
// 添加多个特定组的所有jobs
scheduler.getListenerManager().addJobListener(myJobListener, or(jobGroupEquals("myJobGroup"), jobGroupEquals("yourGroup")));
// 添加所有jobs
scheduler.getListenerManager().addJobListener(myJobListener, allJobs());


有了Listeners以后,当应用需要在某些事件发生以后去通知你的应用,这时就不需要Job去明确地去告知你的应用了。


完整示例

添加一个jobListener,监听到job1执行后,再触发一个job2任务

Job1.java

package com.xgj.quartz.quartzItself.listener.jobListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
public class Job1 implements Job {
  public void execute(JobExecutionContext context)
      throws JobExecutionException {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    JobKey jobKey = context.getJobDetail().getKey();
    System.out.println("\nJob1 - 任务key "
        + jobKey
        + "执行时间:"
        + sdf.format(new Date()));
  }
}


Job2.java

package com.xgj.quartz.quartzItself.listener.jobListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
public class Job2 implements Job {
  public void execute(JobExecutionContext context)
      throws JobExecutionException {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    JobKey jobKey = context.getJobDetail().getKey();
    System.err.println("\nJob2 - 任务key "
        + jobKey
        + "执行时间:"
        + sdf.format(new Date()));
  }
}


自定义JobListener

package com.xgj.quartz.quartzItself.listener.jobListener;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
/**
 * 
 * 
 * @ClassName: MyJobListener
 * 
 * @Description: 自定义Job监听器
 * 
 *               getName() :返回一个字符串用以说明 JobListener 的名称。对于注册为全局的监听器,getName()
 *               主要用于记录日志,对于由特定 Job 引用的 JobListener,注册在 JobDetail
 *               上的监听器名称必须匹配从监听器上 getName() 方法的返回值.
 * 
 *               jobToBeExecuted() :Scheduler 在 JobDetail 将要被执行时调用这个方法。
 * 
 *               jobExecutionVetoed() :Scheduler 在 JobDetail 即将被执行,但又被
 *               TriggerListener 否决了时调用这个方法。
 * 
 *               jobWasExecuted() :Scheduler 在 JobDetail 被执行之后调用这个方法。
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年11月16日 下午3:57:35
 */
public class MyJobListener implements JobListener {
  @Override
  public String getName() {
    return "MyJobListerner";
  }
  @Override
  public void jobToBeExecuted(JobExecutionContext context) {
    System.out.println("Job监听器:MyJobListener.jobToBeExecuted()");
  }
  @Override
  public void jobExecutionVetoed(JobExecutionContext context) {
    System.out.println("Job监听器:MyJobListener.jobExecutionVetoed()");
  }
  @Override
  public void jobWasExecuted(JobExecutionContext context,
      JobExecutionException jobException) {
    System.out.println("Job监听器:MyJobListener.jobWasExecuted()");
     // 设置另外一个job执行
    JobDetail job2 = JobBuilder.newJob(Job2.class).withIdentity("job2")
        .build();
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("job2Trigger").startNow().build();
        try {
      context.getScheduler().scheduleJob(job2, trigger);
        } catch (SchedulerException e) {
            System.err.println("无法安排job2!");
            e.printStackTrace();
        }
  }
}


调度类

package com.xgj.quartz.quartzItself.listener.jobListener;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.JobListener;
import org.quartz.Matcher;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SchedulerMetaData;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.KeyMatcher;
public class JobListenerDemo {
  public static void main(String[] args) throws Exception {
    System.out.println("------- 初始化 ----------------------");
    // Scheduler
    SchedulerFactory schedulerFactory = new StdSchedulerFactory();
    Scheduler scheduler = schedulerFactory.getScheduler();
    // Job
    JobDetail job = newJob(Job1.class).withIdentity("job1", "group1")
        .build();
    // Tirgger 
    Trigger trigger = newTrigger().withIdentity("trigger1", "group1")
        .startNow()
        .build();
    // 设置监听器
    JobListener jobListener = new MyJobListener();
    Matcher<JobKey> matcher = KeyMatcher.keyEquals(job.getKey());
    scheduler.getListenerManager().addJobListener(jobListener, matcher);
    // 将job任务加入到调度器
    scheduler.scheduleJob(job, trigger);
    // 开始任务
    System.out.println("------- 开始执行调度器 Scheduler ----------------");
    scheduler.start();
    try {
      System.out.println("------- 等待 30 秒... --------------");
      Thread.sleep(30L * 1000L);
    } catch (Exception e) {
      e.printStackTrace();
    }
    scheduler.shutdown(true);
    System.out.println("------- 关闭调度器 -----------------");
    SchedulerMetaData metaData = scheduler.getMetaData();
    System.out.println("~~~~~~~~~~  执行了 "
        + metaData.getNumberOfJobsExecuted() + " 个 jobs.");
  }
}


运行结果

------- 初始化 ----------------------
INFO  StdSchedulerFactory - Using default implementation for ThreadExecutor
INFO  SimpleThreadPool - Job execution threads will use class loader of thread: main
INFO  SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
INFO  QuartzScheduler - Quartz Scheduler v.2.2.3 created.
INFO  RAMJobStore - RAMJobStore initialized.
INFO  QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.2.3) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
INFO  StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
INFO  StdSchedulerFactory - Quartz scheduler version: 2.2.3
------- 开始执行调度器 Scheduler ----------------
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
------- 等待 30 秒... --------------
Job监听器:MyJobListener.jobToBeExecuted()
Job1 - 任务key group1.job1执行时间:2017-11-16 17:58:54
Job监听器:MyJobListener.jobWasExecuted()
Job2 - 任务key DEFAULT.job2执行时间:2017-11-16 17:58:54
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
INFO  QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.
------- 关闭调度器 -----------------
~~~~~~~~~~  执行了 2 个 jobs.


示例源码


代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

相关文章
|
SQL Java 关系型数据库
quartz
quartz
129 0
|
API
Quartz-DateBuilder解读
Quartz-DateBuilder解读
111 0
Quartz-SimpleTrigger解读
Quartz-SimpleTrigger解读
89 0
|
调度
Quartz-TriggerListener解读
Quartz-TriggerListener解读
70 0
quartz学习笔记7:trading
quartz学习笔记7:trading
81 0
|
存储 安全 Java
Quartz 是什么?一文带你入坑
本文主要介绍 Quartz 的使用
718 0
|
Java Spring
Quartz - Quartz之Spring整合篇
Quartz - Quartz之Spring整合篇
134 0
Quartz - Quartz之Spring整合篇
|
Java 应用服务中间件
Quartz - 基础篇(下)
Quartz - 基础篇(下)
176 0
Quartz - 基础篇(下)
Quartz - 基础篇(上)
Quartz - 基础篇(上)
124 0
Quartz - 基础篇(上)
|
Java 调度 Spring
Spring定时任务的实现:Quartz
Spring定时任务的实现:Quartz
172 0
Spring定时任务的实现:Quartz