zoukankan      html  css  js  c++  java
  • Quartz任务调度(4)JobListener分版本超详细解析

    JobListener

    我们的jobListener实现类必须实现其以下方法:

    方法说明
    getName() getName() 方法返回一个字符串用以说明 JobListener 的名称。对于注册为全局的监听器,getName() 主要用于记录日志,对于由特定 Job 引用的 JobListener,注册在 JobDetail 上的监听器名称必须匹配从监听器上 getName() 方法的返回值。
    jobToBeExecuted() Scheduler 在 JobDetail 将要被执行时调用这个方法。
    jobExecutionVetoed() Scheduler 在 JobDetail 即将被执行,但又被 TriggerListener 否决了时调用这个方法。
    jobWasExecuted() Scheduler 在 JobDetail 被执行之后调用这个方法。

    接下来我们以Quartz任务调度(1)概念例析快速一文中的定时扒取新闻任务和获得最热新闻任务为例,分析我们的监听器方法。

    1. 自定义监听器接口实现类

    public class MyJobListener implements JobListener {
    
        @Override//相当于为我们的监听器命名
        public String getName() {
            return "myJobListener";
        }
    
        @Override
        public void jobToBeExecuted(JobExecutionContext context) {
            System.out.println(getName() + "触发对"+context.getJobDetail().getJobClass()+"的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录");
        }
    
        @Override//“否决JobDetail”是在Triiger被其相应的监听器监听时才具备的能力
        public void jobExecutionVetoed(JobExecutionContext context) {
            System.out.println("被否决执行了,可以做些日志记录。");
        }
    
        @Override
        public void jobWasExecuted(JobExecutionContext context,
                JobExecutionException jobException) {
            System.out.println(getName() + "触发对"+context.getJobDetail().getJobClass()+"结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作");
    
        }
    
    }

    2. 在scheduler中注册监听器

    这里有两种方式,一种是注册为全局监听器,对所有的JobDetail都有效,另一种是注册为针对特定JobDetail的局部监听器。针对不同的版本,有不同的配置方式

    1. 准备工作

    在测试中我们用到工作实现类为

    public class PickNewsJob implements Job {
    
        @Override
        public void execute(JobExecutionContext jec) throws JobExecutionException {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            System.out.println("在" + sdf.format(new Date()) + "扒取新闻");
        }
    }
    
    public class GetHottestJob implements Job {
    
        @Override
        public void execute(JobExecutionContext jec) throws JobExecutionException {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            System.out.println("在" + sdf.format(new Date()) +"根据文章的阅读量和评论量来生成我们的最热文章列表");
        }
    
    }

    2. 1.x版本配置

    在1.+版本中,我们可以通过如下代码监听job

    /**********局部监听器配置**********/
    JobListener myJobListener = new MyJobListener();
    pickNewsJob.addJobListener("myJobListener");//这里的名字和myJobListener中getName()方法的名字一样
    scheduler.addJobListener(myJobListener);//向scheduler注册我们的监听器
    /*********全局监听器配置************/
    JobListener myJobListener = new MyJobListener();
    scheduler.addGlobalJobListener(myJobListener);//直接添加为全局监听器

    下面是我们的完整测试代码:

    public static void main(String args[]) throws SchedulerException {
        JobDetail pickNewsJob =new JobDetail("job1", "jgroup1", PickNewsJob.class); 
        JobDetail getHottestJob =new JobDetail("job2", "jgroup2", GetHottestJob.class);
        SimpleTrigger pickNewsTrigger = new SimpleTrigger("trigger1", "group1",1,2000);
        SimpleTrigger getHottestTrigger = new SimpleTrigger("trigger2", "group2",1,3000);
    
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
    
        /**********局部监听器配置**********/
        JobListener myJobListener = new MyJobListener();
        pickNewsJob.addJobListener("myJobListener");//这里的名字和myJobListener中getName()方法的名字一样
        scheduler.addJobListener(myJobListener);//向scheduler注册我们的监听器
        /*********全局监听器配置************/
    //      JobListener myJobListener = new MyJobListener();
    //      scheduler.addGlobalJobListener(myJobListener);//直接添加为全局监听器
    
        scheduler.scheduleJob(pickNewsJob,pickNewsTrigger);
        scheduler.scheduleJob(getHottestJob,getHottestTrigger);
    
        scheduler.start();
    
    }

    现在是使用局部监听器的配置,运行程序,控制台打印:

    myJobListener触发对class tool.job.PickNewsJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    在11:18:31扒取新闻
    在11:18:31根据文章的阅读量和评论量来生成我们的最热文章列表————————从这里我们可以看出两个工作是异步进行的
    myJobListener触发对class tool.job.PickNewsJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    myJobListener触发对class tool.job.PickNewsJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    在11:18:33扒取新闻
    myJobListener触发对class tool.job.PickNewsJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    在11:18:34根据文章的阅读量和评论量来生成我们的最热文章列表
    我们细心观察还会发现,我们两个工作都运行了三次,但我们在配置触发器时,repeatCount都是设为2。这说明我们的任务调度特点是:主执行了1次,重复了2次,于是共执行3(1+repeatCount)次。

    如果我们注释掉局部监听代码,启用全局监听,会看到控制台打印:

    myJobListener触发对class tool.job.PickNewsJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    myJobListener触发对class tool.job.GetHottestJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    在11:25:41扒取新闻
    在11:25:41根据文章的阅读量和评论量来生成我们的最热文章列表
    myJobListener触发对class tool.job.GetHottestJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    myJobListener触发对class tool.job.PickNewsJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    myJobListener触发对class tool.job.PickNewsJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    在11:25:43扒取新闻
    myJobListener触发对class tool.job.PickNewsJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    myJobListener触发对class tool.job.GetHottestJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    在11:25:44根据文章的阅读量和评论量来生成我们的最热文章列表
    myJobListener触发对class tool.job.GetHottestJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    即我们的两个任务都被监听了

    3. 2.x版本配置

    在2.+版本中,引入了**org.quartz.ListenerManager和org.quartz.Matcher
    **来对我们的监听器进行更细粒度的管理配置

    1. ListenerManager

    我们通过ListenerManager向scheduler中添加我们的监听器。它针对JobDetail的常用方法有:
    1. public void addJobListener(JobListener jobListener)
    添加全局监听器,即所有JobDetail都会被此监听器监听
    2. public void addJobListener(JobListener jobListener, Matcher matcher)
    添加带条件匹配的监听器,在matcher中声明我们的匹配条件
    3. public void addJobListener(JobListener jobListener, Matcher … matchers)
    添加附带不定参条件陪陪的监听器
    4. public boolean removeJobListener(String name)
    根据名字移除JobListener
    5. public List getJobListeners()
    获取所有的监听器
    6. public JobListener getJobListener(String name)
    根据名字获取监听器

    2. matcher

    我们通过matcher让不同的监听器监听不同的任务。它有很多实现类,先逐一分析如下:

    1. KeyMatcher<JobKey>

    根据JobKey进行匹配,每个JobDetail都有一个对应的JobKey,里面存储了JobName和JobGroup来定位唯一的JobDetail。它的常用方法有:

        /************构造Matcher方法************/
        KeyMatcher<JobKey> keyMatcher = KeyMatcher.keyEquals(pickNewsJob.getKey());//构造匹配pickNewsJob中的JobKey的keyMatcher。
    
        /*********使用方法************/
        scheduler.getListenerManager().addJobListener(myJobListener, keyMatcher);//通过这句完成我们监听器对pickNewsJob的唯一监听
    2. GroupMatcher

    根据组名信息匹配,它的常用方法有:

        GroupMatcher<JobKey> groupMatcher = GroupMatcher.jobGroupContains("group1");//包含特定字符串
                GroupMatcher.groupEndsWith("oup1");//以特定字符串结尾
                GroupMatcher.groupEquals("jgroup1");//以特定字符串完全匹配
                GroupMatcher.groupStartsWith("jgou");//以特定字符串开头
    3. AndMatcher

    对两个匹配器取交集,实例如下:

    KeyMatcher<JobKey> keyMatcher = KeyMatcher.keyEquals(pickNewsJob.getKey());
    GroupMatcher<JobKey> groupMatcher = GroupMatcher.jobGroupContains("group1");
    AndMatcher<JobKey> andMatcher = AndMatcher.and(keyMatcher,groupMatcher);//同时满足两个入参匹配
    4. OrMatcher

    对两个匹配器取并集,实例如下:

    OrMatcher<JobKey> orMatcher = OrMatcher.or(keyMatcher, groupMatcher);//满足任意一个即可
    5. EverythingMatcher

    局部全局匹配,它有两个构造方法:

    EverythingMatcher.allJobs();//对全部JobListener匹配
    EverythingMatcher.allTriggers();//对全部TriggerListener匹配

    下面是我们的完整测试测序:

    public static void main(String args[]) throws SchedulerException {
        final JobDetail pickNewsJob = JobBuilder.newJob(PickNewsJob.class)
                .withIdentity("job1", "jgroup1").build();
        JobDetail getHottestJob = JobBuilder.newJob(GetHottestJob.class)
                .withIdentity("job2", "jgroup2").build();
        SimpleTrigger pickNewsTrigger = TriggerBuilder
                .newTrigger()
                .withIdentity("trigger1","tgroup1")
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(2, 1)).startNow()
                .build();
        SimpleTrigger getHottestTrigger = TriggerBuilder
                .newTrigger()
                .withIdentity("trigger2","tgroup2")
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(2, 2)).startNow()
                .build();
        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        JobListener myJobListener = new MyJobListener();
        KeyMatcher<JobKey> keyMatcher = KeyMatcher.keyEquals(pickNewsJob.getKey());
        scheduler.getListenerManager().addJobListener(myJobListener, keyMatcher);
        scheduler.scheduleJob(pickNewsJob, pickNewsTrigger);
        scheduler.scheduleJob(getHottestJob,getHottestTrigger);
        scheduler.start();
    }

    运行程序,我们得到下列打印信息:

    myJobListener触发对class tool.job.PickNewsJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    根据文章的阅读量和评论量来生成我们的最热文章列表
    在12:48:58扒取新闻
    myJobListener触发对class tool.job.PickNewsJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    myJobListener触发对class tool.job.PickNewsJob的开始执行的监听工作,这里可以完成任务前的一些资源准备工作或日志记录
    在12:48:59扒取新闻
    myJobListener触发对class tool.job.PickNewsJob结束执行的监听工作,这里可以进行资源销毁工作或做一些新闻扒取结果的统计工作
    根据文章的阅读量和评论量来生成我们的最热文章列表
    显然,myJobListener只和我们的PickNewsJob匹配了。
    关于测试代码的其他配置可移步参考本系列前面的文章,里面都有详细的配置实例讲解

  • 相关阅读:
    一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)
    步步为营UML建模系列七、表图(Data model diagram)
    步步为营UML建模系列六、类图(Class diagram)
    WebEx
    使用Nancy和Simple.Data两个轻量级的框架打造一个分布式开发系统
    细说 ASP.NET控制HTTP缓存
    WCSF vs ASP.NET MVC
    使用KTM(内核事务管理器)进行文件事务处理
    .net 2.0下的OOXML神器:NPOI.OpenXml4Net
    为什么System.Attribute的GetHashCode方法需要如此设计?
  • 原文地址:https://www.cnblogs.com/deityjian/p/11680784.html
Copyright © 2011-2022 走看看