1.概念
Quartz的监听器用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知。类似
于任务执行过程中的邮件、短信类的提醒。Quartz监听器主要有JobListener
TriggerListenerSchedulerListener三种,顾名思义,分别表示任务、触发器、调度器对应的
监听器。三者的使用方法类似,在开始介绍三种监听器之前,需要明确两个概念:全局监听器
与非全局监听器,二者的区别在于:
全局监听器能够接收到所有的Job/Trigger的事件通知,
而非全局监听器只能接收到在其上注册的JobTrigger的事件,不在其上注册的JobTrigger
不会进行监听。
2.JobListener
任务调度过程中,与任务Job相关的事件包括:job开始要执行的提示; job执行完成的提示。

public interface JobListener {

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Interface.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    /**
     * <p>
     * Get the name of the <code>JobListener</code>.
     * </p>
     */
    String getName();

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * is about to be executed (an associated <code>{@link Trigger}</code>
     * has occurred).
     * </p>
     * 
     * <p>
     * This method will not be invoked if the execution of the Job was vetoed
     * by a <code>{@link TriggerListener}</code>.
     * </p>
     * 
     * @see #jobExecutionVetoed(JobExecutionContext)
     */
    void jobToBeExecuted(JobExecutionContext context);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * was about to be executed (an associated <code>{@link Trigger}</code>
     * has occurred), but a <code>{@link TriggerListener}</code> vetoed it's 
     * execution.
     * </p>
     * 
     * @see #jobToBeExecuted(JobExecutionContext)
     */
    void jobExecutionVetoed(JobExecutionContext context);

    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> after a <code>{@link org.quartz.JobDetail}</code>
     * has been executed, and be for the associated <code>Trigger</code>'s
     * <code>triggered(xx)</code> method has been called.
     * </p>
     */
    void jobWasExecuted(JobExecutionContext context,
            JobExecutionException jobException);

}

创建自定义的JobListener
MyJobListener.java

public class MyJobListener implements JobListener {

    @Override
    public String getName() {
        String name = getClass().getSimpleName();
        System.out.println("监听器的名称是:" + name);
        return name;
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext context) {
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Job的名称是:" + jobName + "     Scheduler在JobDetail将要被执行时调用这个方法");
    }

    @Override
    public void jobExecutionVetoed(JobExecutionContext context) {
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Job的名称是:" + jobName + "     Scheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法");
    }

    @Override
    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        String jobName = context.getJobDetail().getKey().getName();
        System.out.println("Job的名称是:" + jobName + "     Scheduler在JobDetail被执行之后调用这个方法");
    }
}

执行调度器
HelloSchedulerDemoJobListener.java

public class HelloSchedulerDemoJobListener {

    public static void main(String[] args) throws Exception {
        // 1:从工厂中获取任务调度的实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
        JobDetail job = JobBuilder.newJob(HelloJobListener.class).withIdentity("job1", "group1") // 定义该实例唯一标识
                .build();
        // 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
        @SuppressWarnings("static-access")
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") // 定义该实例唯一标识
                .startNow() // 马上执行
                // .startAt(triggerStartTime) // 针对某个时刻执行
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(5)) // 每5秒执行一次
                .build();

        // 4:使用触发器调度任务的执行
        scheduler.scheduleJob(job, trigger);

        // 创建并注册一个全局的Job Listener
        scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());
        // 创建并注册一个指定任务的Job Listener
        // scheduler.getListenerManager().addJobListener(new MyJobListener(),
        // KeyMatcher.keyEquals(JobKey.jobKey("job1", "group1")));
        // 5:开启
        scheduler.start();
        // 关闭
        // scheduler.shutdown();
    }

}
执行结果:
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail将要被执行时调用这个方法
进行数据库备份操作。当前任务执行的时间:2019-05-12 22:09:15
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail被执行之后调用这个方

3.TriggerListener
任务调度过程中,与触发器Trigger相关的事件包括:触发器触发、触发器未正常触发、触发器
完成等。

public interface TriggerListener {
    public String getName();
    public void triggerFired(Trigger trigger, JobExecutionContext context);
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);
    public void triggerMisfired(Trigger trigger);
    public void triggerComplete(Trigger trigger, JobExecutionContext context, int triggerInstructionCode);
}

其中:
1) getName方法:用于获取触发器的名称
2) triggerFired方法:当与监听器相关联的Trigger被触发,Job上的execute()方法将被执行时,
Scheduler就调用该方法。
3) vetoJobExecution方法:在 Trigger 触发后,Job 将要被执行时由 Scheduler 调用这个方
法。TriggerListener 给了一个选择去否决 Job 的执行。假如这个方法返回 true,这个 Job 将不
会为此次 Trigger 触发而得到执行。
4) triggerMisfired方法:Scheduler 调用这个方法是在 Trigger 错过触发时。你应该关注此方
法中持续时间长的逻辑:在出现许多错过触发的 Trigger 时,长逻辑会导致骨牌效应。你应当
保持这上方法尽量的小。
5) triggerComplete方法:Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方
法。
示例:
下面的例子简单展示了TriggerListener的使用,其中创建并注册TriggerListenerJobListener
几乎类似。
HelloJobListener.j ava

public class HelloJobListener implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // TODO Auto-generated method stub
        // 定义时间
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);

        // 定义工作任务内容
        System.out.println("进行数据库备份操作。当前任务执行的时间:" + dateString);

    }

}
public class MyTriggerListener implements TriggerListener {
    private String name;

    public MyTriggerListener(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        String name = getClass().getSimpleName();
        System.out.println("监听器的名称是:" + name);
        return name;
    }

    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext context) {
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 被触发");
    }

    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 没有被触发");
        return false; // true:表示不会执行Job的方法
    }

    @Override
    public void triggerMisfired(Trigger trigger) {
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 错过触发");
    }

    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext context,
            CompletedExecutionInstruction triggerInstructionCode) {
        String triggerName = trigger.getKey().getName();
        System.out.println(triggerName + " 完成之后触发");
    }

}
public class HelloSchedulerDemoTriggerListener {
    @SuppressWarnings("static-access")
    public static void main(String[] args) throws Exception {
        // 1:从工厂中获取任务调度的实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
        JobDetail job = JobBuilder.newJob(HelloJobListener.class).withIdentity("job5", "group5") // 定义该实例唯一标识
                .build();
        // 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger5", "group5") // 定义该实例唯一标识
                .startNow() // 马上执行
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(5)) // 每5秒执行一次
                .build();

        // 4:使用触发器调度任务的执行
        scheduler.scheduleJob(job, trigger);

        // 创建并注册一个全局的Trigger Listener
        scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());
        scheduler.getListenerManager().addTriggerListener(new MyTriggerListener("simpleTrigger"));
        // 创建SchedulerListener
        scheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());
        // 创建SchedulerListener
        // scheduler.getListenerManager().addSchedulerListener(new
        // MySchedulerListener());
        // 创建并注册一个局部的Trigger Listener
        // scheduler.getListenerManager().addTriggerListener(new
        // MyTriggerListener("simpleTrigger"),
        // KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1", "group1")));

        // 5:开启
        scheduler.start();
        // 关闭
        // scheduler.shutdown();
    }

}
结果
:(当为true的时候)
trigger1 被触发
trigger1 没有被触发
trigger1 被触发
trigger1 没有被触发
trigger1 被触发
trigger1 没有被触发
=======================================
结果:(当为false的时候)
监听器的名称是:MyTriggerListener
trigger1 被触发
trigger1 没有被触发
进行数据库备份操作。当前任务执行的时间:2019-05-12 22:33:43
trigger1 完成之后触发
=========================================
结果:当监听2个监听器的时候
监听器的名称是:MyTriggerListener
trigger1 被触发
trigger1 没有被触发
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail将要被执行时调用这个方法
进行数据库备份操作。当前任务执行的时间:2019-05-12 22:41:26
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail被执行之后调用这个方法
监听器的名称是:MyTriggerListener
trigger1 完成之后触发

4.SchedulerListener
SchedulerListener会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的
事件包括:增加一个job/trigger,删除一个job/triggerscheduler发生严重错误,关闭
scheduler等。

public interface SchedulerListener {

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Interface.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * is scheduled.
     * </p>
     */
    void jobScheduled(Trigger trigger);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * is unscheduled.
     * </p>
     * 
     * @see SchedulerListener#schedulingDataCleared()
     */
    void jobUnscheduled(TriggerKey triggerKey);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>
     * has reached the condition in which it will never fire again.
     * </p>
     */
    void triggerFinalized(Trigger trigger);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>
     * has been paused.
     * </p>
     */
    void triggerPaused(TriggerKey triggerKey);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a 
     * group of <code>{@link Trigger}s</code> has been paused.
     * </p>
     * 
     * <p>If all groups were paused then triggerGroup will be null</p>
     * 
     * @param triggerGroup the paused group, or null if all were paused
     */
    void triggersPaused(String triggerGroup);
    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>
     * has been un-paused.
     * </p>
     */
    void triggerResumed(TriggerKey triggerKey);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a 
     * group of <code>{@link Trigger}s</code> has been un-paused.
     * </p>
     */
    void triggersResumed(String triggerGroup);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * has been added.
     * </p>
     */
    void jobAdded(JobDetail jobDetail);
    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * has been deleted.
     * </p>
     */
    void jobDeleted(JobKey jobKey);
    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * has been paused.
     * </p>
     */
    void jobPaused(JobKey jobKey);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a 
     * group of <code>{@link org.quartz.JobDetail}s</code> has been paused.
     * </p>
     * 
     * @param jobGroup the paused group, or null if all were paused
     */
    void jobsPaused(String jobGroup);
    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a <code>{@link org.quartz.JobDetail}</code>
     * has been un-paused.
     * </p>
     */
    void jobResumed(JobKey jobKey);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a 
     * group of <code>{@link org.quartz.JobDetail}s</code> has been un-paused.
     * </p>
     */
    void jobsResumed(String jobGroup);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> when a serious error has
     * occurred within the scheduler - such as repeated failures in the <code>JobStore</code>,
     * or the inability to instantiate a <code>Job</code> instance when its
     * <code>Trigger</code> has fired.
     * </p>
     * 
     * <p>
     * The <code>getErrorCode()</code> method of the given SchedulerException
     * can be used to determine more specific information about the type of
     * error that was encountered.
     * </p>
     */
    void schedulerError(String msg, SchedulerException cause);

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> to inform the listener
     * that it has move to standby mode.
     * </p>
     */
    void schedulerInStandbyMode();

    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> to inform the listener
     * that it has started.
     * </p>
     */
    void schedulerStarted();
    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> to inform the listener
     * that it is starting.
     * </p>
     */
    void schedulerStarting();
    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> to inform the listener
     * that it has shutdown.
     * </p>
     */
    void schedulerShutdown();
    
    /**
     * <p>
     * Called by the <code>{@link Scheduler}</code> to inform the listener
     * that it has begun the shutdown sequence.
     * </p>
     */
    void schedulerShuttingdown();

    /**
     * Called by the <code>{@link Scheduler}</code> to inform the listener
     * that all jobs, triggers and calendars were deleted.
     */
    void schedulingDataCleared();
}

其中:
1) jobScheduled方法:用于部署JobDetail时调用
2) jobUnscheduled方法:用于卸载JobDetail时调用
3) triggerFinalized方法:当一个 Trigger 来到了再也不会触发的状态时调用这个方法。除非这个 Job 已设置成了持久性,否则它就会从 Scheduler 中移除。
4) triggersPaused方法:Scheduler 调用这个方法是发生在一个 Trigger Trigger 组被暂停时。假如是 Trigger 组的话,triggerName 参数将为 null
5) triggersResumed方法:Scheduler 调用这个方法是发生成一个 Trigger Trigger 组从暂停中恢复时。假如是 Trigger 组的话,假如是 Trigger 组的话,triggerName 参数将为 null。参数将为 null
 6) jobsPaused方法:当一个或一组 JobDetail 暂停时调用这个方法。

7)jobsResumed方法:当一个或一组 Job 从暂停上恢复时调用这个方法。假如是一个 Job 组,jobName 参数将为 null
 8) schedulerError方法:在 Scheduler 的正常运行期间产生一个严重错误时调用这个方法。
9) schedulerStarted方法:当Scheduler 开启时,调用该方法
10)schedulerInStandbyMode方法: 当Scheduler处于StandBy模式时,调用该方法
11)schedulerShutdown方法:当Scheduler停止时,调用该方法
12) schedulingDataCleared法:当Scheduler中的数据被清除时,调用该方法。
示例:
下面的代码简单描述了如何使用SchedulerListener方法:
HelloJobListener.java

public class HelloJobListener implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // TODO Auto-generated method stub
        // 定义时间
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);

        // 定义工作任务内容
        System.out.println("进行数据库备份操作。当前任务执行的时间:" + dateString);

    }

}
public class MySchedulerListener implements SchedulerListener {
    @Override
    public void jobScheduled(Trigger trigger) {
        String jobName = trigger.getJobKey().getName();
        System.out.println(jobName + " 完成部署");
    }

    @Override
    public void jobUnscheduled(TriggerKey triggerKey) {
        System.out.println(triggerKey + " 完成卸载");
    }

    @Override
    public void triggerFinalized(Trigger trigger) {
        System.out.println("触发器被移除 " + trigger.getJobKey().getName());
    }

    @Override
    public void triggerPaused(TriggerKey triggerKey) {
        System.out.println(triggerKey + " 正在被暂停");
    }

    @Override
    public void triggersPaused(String triggerGroup) {
        System.out.println("触发器组 " + triggerGroup + " 正在被暂停");
    }

    @Override
    public void triggerResumed(TriggerKey triggerKey) {
        System.out.println(triggerKey + " 正在从暂停中恢复");
    }

    @Override
    public void triggersResumed(String triggerGroup) {
        System.out.println("触发器组 " + triggerGroup + " 正在从暂停中恢复");
    }

    @Override
    public void jobAdded(JobDetail jobDetail) {
        System.out.println(jobDetail.getKey() + " 添加工作任务");
    }

    @Override
    public void jobDeleted(JobKey jobKey) {
        System.out.println(jobKey + " 删除工作任务");
    }

    @Override
    public void jobPaused(JobKey jobKey) {
        System.out.println(jobKey + " 工作任务正在被暂停");
    }

    @Override
    public void jobsPaused(String jobGroup) {
        System.out.println("工作任务组 " + jobGroup + " 正在被暂停");
    }

    @Override
    public void jobResumed(JobKey jobKey) {
        System.out.println(jobKey + " 正在从暂停中恢复");
    }

    @Override
    public void jobsResumed(String jobGroup) {
        System.out.println("工作任务组 " + jobGroup + " 正在从暂停中恢复");
    }

    @Override
    public void schedulerError(String msg, SchedulerException cause) {
        System.out.println("产生严重错误时调用:   " + msg + "  " + cause.getUnderlyingException());
    }

    @Override
    public void schedulerInStandbyMode() {
        System.out.println("调度器在挂起模式下调用");
    }

    @Override
    public void schedulerStarted() {
        System.out.println("调度器 开启时调用");
    }

    @Override
    public void schedulerStarting() {
        System.out.println("调度器 正在开启时调用");
    }

    @Override
    public void schedulerShutdown() {
        System.out.println("调度器 已经被关闭 时调用");
    }

    @Override
    public void schedulerShuttingdown() {
        System.out.println("调度器 正在被关闭 时调用");
    }

    @Override
    public void schedulingDataCleared() {
        System.out.println("调度器的数据被清除时调用");
    }

}
public class HelloSchedulerDemoSchedulerListener {
    public static void main(String[] args) throws Exception {
        // 1:从工厂中获取任务调度的实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 2:定义一个任务调度实例,将该实例与HelloJob绑定,任务类需要实现Job接口
        JobDetail job = JobBuilder.newJob(HelloJobListener.class).withIdentity("job1", "group1") // 定义该实例唯一标识
                .build();
        // 3:定义触发器 ,马上执行, 然后每5秒重复执行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") // 定义该实例唯一标识
                .startNow() // 马上执行
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(5)) // 每5秒执行一次
                .build();

        // 4:使用触发器调度任务的执行
        Date scheduleJob = scheduler.scheduleJob(job, trigger);

        // 创建SchedulerListener
        scheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());
        scheduler.getListenerManager().addTriggerListener(new MyTriggerListener("simpleTrigger"));
        scheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());

        // 移除对应的SchedulerListener
        // scheduler.getListenerManager().removeSchedulerListener(new
        // MySchedulerListener());

        // 5:开启
        scheduler.start();
        // 延迟7秒后关闭
        Thread.sleep(7000);
        // 关闭
        scheduler.shutdown();
    }

}
调度
器 正在开启时调用
23:01:03,174 INFO QuartzScheduler:547 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED started.
调度器 开启时调用
进行数据库备份操作。当前任务执行的时间:2019-05-12 23:01:03
进行数据库备份操作。当前任务执行的时间:2019-05-12 23:01:08
23:01:10,178 INFO QuartzScheduler:666 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
23:01:10,179 INFO QuartzScheduler:585 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED paused.
调度器在挂起模式下调用
调度器 正在被关闭 时调用
调度器 已经被关闭 时调用
23:01:10,181 INFO QuartzScheduler:740 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.
调度器 正在开启时调用
23:10:21,011 INFO QuartzScheduler:547 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED started.
调度器 开启时调用
监听器的名称是:MyTriggerListenertrigger1 被触发
trigger1 没有被触发
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail将要被执行时调用这个方法
进行数据库备份操作。当前任务执行的时间:2019-05-12 23:10:21
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail被执行之后调用这个方法
监听器的名称是:MyTriggerListener
trigger1 完成之后触发
=======================================
监听器的名称是:MyTriggerListener
trigger1 被触发
trigger1 没有被触发
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail将要被执行时调用这个方法
进行数据库备份操作。当前任务执行的时间:2019-05-12 23:10:26
监听器的名称是:MyJobListener
Job的名称是:job1 Scheduler在JobDetail被执行之后调用这个方法
监听器的名称是:MyTriggerListener
trigger1 完成之后触发
========================================
23:10:28,021 INFO QuartzScheduler:666 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
23:10:28,021 INFO QuartzScheduler:585 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED paused.
调度器在挂起模式下调用
调度器 正在被关闭 时调用
调度器 已经被关闭 时调用
23:10:28,022 INFO QuartzScheduler:740 - Scheduler
DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete