quartz - 基础知识

1. Quartz 设计模式

  • Bulider模式  
  • Factory模式
  • 组件模式
  • 链式编程

2. Quartz两种执行模式

  RAMJobStore :

  RAMJobStore是默认的数据存储方式,其把数据存在本地内存中,官方宣称这是最有效率的方式(在本地内存当然快啦)。但是在宕机或者重启的时候数据就会丢失。

 

  JDBCJobStore:

  JDBCJobStore终于把数据给持久化起来了,这个也是使用最广泛的数据存储方式。在于Spring集成后都不需要自己再配置一遍数据库连接了。建表脚本在官方包里面可以找到(http://www.quartz-scheduler.org/downloads/)

 

3. Quartz核心概念(通过quartz工厂获取这三个组件)

  * 调度器Scheduler

  Scheduler将任务Job和触发器Trigger整合起来,负责基于Trigger设定的时间去执行任务Job;

  Scheduler作为我们的“任务记录表”,里面(可以)配置大量的Trigger和JobDetail,两者在 Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。

  SchedulerFactory schedulerFactory = new StdSchedulerFactory();
  Scheduler scheduler = schedulerFactory.getScheduler();//将jobDetail和Trigger注册到一个scheduler里,建立起两者的关联关系
  scheduler.scheduleJob(jobDetail,Trigger);
  scheduler.start();//开始任务调度

 

  * 任务Job

  job就是你想要实现的任务类,每一个job必须实现org.quartz.job接口,且只需时间接口定义的execu()方法;

public class IapetoseeJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobKey key = context.getJobDetail().getKey();
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();    
        String myString= dataMap.getString("我的字符串");
        int myInt = dataMap.getInteger("我的数字");
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        System.out.println("在"+sdf.format(new Date())+"扒取新闻");
    }
}

 

  * JobDetail补充

  Quartz在每次执行任务时,都会创建一个Job实例,并为其配置上下文信息,jobDetail有一个成员属性JobDataMap,存放了我们Job运行时的具体信息,在后面我们会详细提到。 
  1. 在1.+版本中,它作为一个类,常用的构造方法有:JobDetail(String name, String group, Class jobClass),我们需要指定job的名称,组别和实现了Job接口的自定义任务类。实例如JobDetail jobDetail =new JobDetail("job1", "jgroup1", pickNewsJob.class); 
  2. 而在2.+版本中,我们则通过一下方法创建 JobBuilder.newJob(自定义任务类).withIdentity(任务名称,组名).build();实例如JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class).withIdentity(“job1”,”group1”).build();`

  JobDetail job = newJob(IapetoseeJob.class)
      .withIdentity("任务名称", "组名") 
      .usingJobData("我的字符串", "Hello World!").usingJobData("我的数字",12341234)
      .build();

    * 触发器Trigger

  Trigger描述了Job执行的时间触发规则,主要有SimpleTrigger和CronTrigger两个子类。

  SimpleTrigger simpleTrigger = TriggerBuilde.newTrigger() 
.withIdentity("trigger1")//配置触发器名称 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2))//配置重复次数和间隔时间 .startNow()//设置从当前开始 .build();//创建操作

 4. 简单实现过程

  public static void main(String[] args) throws SchedulerException {
        //获得调度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //创建任务实例
        JobDetail jobDetail = JobBuilder.newJob(QiyeJob.class).withIdentity("qiye", "gongshang").build();
        //创建任务执行条件
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("qiyeTrigger", "gongshangqiyeTrigger").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).startNow().build();
        //关联任务
        scheduler.scheduleJob(jobDetail,trigger);
        //执行任务
        scheduler.start();
    }

 5. 有状态的job

  Quartz,每次执行job,job永远是全新的对象,但是,如果job实现org.quartz.StatefulJob接口,而不是job接口.

  此时JobDetail的JobDataMap将会共享一个对象。
  注意:
    当实现有状态接口,StatefulJob时,只有JobDetail的JobDataMap是共用的,其他的,比如,Job本身,Trigger等,仍然每次执行 的时候是全新的对象。所以,只有JobDetail的JobDataMap是共用的,其他的trigger.getJobDataMap(),context.getMergedJobDataMap(),等这些JobDataMap,任然是全新的
6.  StdSchedulerFactory和DirectSchedulerFactory的区别

  StdSchedulerFactory

  StdSchedulerFactory是对org.quartz.SchedulerFactory接口的一个实现。是使用一套属性(NameValueCollection)来创建和初始化Quartz Scheduler。这些属性通常在文件中存储和加载。也可以通过编写程序来直接操作工厂。简单地调用工厂的getScheduler()就可以产生一个scheduler,初始化(以及它的ThreadPool、JobStore和DataSources),并且返回一个公共的接口。

  DirectSchedulerFactory

  DirectSchedulerFactory是SchedulerFactory的另一个实现。它对于那些希望用更加程序化的方式创建Scheduler非常有用。不鼓励使用它的原因如下:

  (1) 它需要用户非常了解他们想要干什么。

  (2) 它不允许声明式的配置。换句话说,它使用硬编码的方式设置scheduler。

7. Quartz监听器

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

  (1)JobListener

    a.  getName方法:用于获取该JobListener的名称。

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

    c.  jobExecutionVetoed方法:Scheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法

    d.  jobWasExecuted方法:Scheduler在JobDetail被执行之后调用这个方法

public class SystemJoblistener implements JobListener {

    @Override
    public String getName() {
        //输出当前监听器的名字
        return this.getClass().getSimpleName();
    }


    @Override
    public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
        //在任务执行之前
        String name = jobExecutionContext.getJobDetail().getKey().getName();
        System.out.println("1 任务:"+name+"执行了");

    }

    @Override
    public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
        //在任务执行被否决的时候
        System.out.println("2 Scheduler在JobDetail即将被执行,但又被TriggerListerner否决时会调用该方法");
    }

    @Override
    public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
        //在任务执行完成之后执行
        String name = jobExecutionContext.getJobDetail().getKey().getName();
        System.out.println("3 任务:"+name+"执行完了");
    }
}

  注册进scheduler中

    //设置全局job监听器
        ListenerManager listenerManager = scheduler.getListenerManager();
        listenerManager.addJobListener(new SystemJoblistener(), EverythingMatcher.allJobs());

  

  (2)TriggerListener

方法说明
getName()定义并返回监听器的名字
triggerFired()当与监听器相关联的 Trigger 被触发,Job 上的 execute() 方法将要被执行时,Scheduler 就调用这个方法。在全局 TriggerListener 情况下,这个方法为所有 Trigger 被调用。
vetoJobExecution()在 Trigger 触发后,Job 将要被执行时由 Scheduler 调用这个方法。TriggerListener 给了一个选择去否决 Job 的执行。假如这个方法返回 true,这个 Job 将不会为此次 Trigger 触发而得到执行。
triggerMisfired()Scheduler 调用这个方法是在 Trigger 错过触发时。如这个方法的 JavaDoc 所指出的,你应该关注此方法中持续时间长的逻辑:在出现许多错过触发的 Trigger 时,长逻辑会导致骨牌效应。你应当保持这上方法尽量的小。
triggerComplete()Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方法。这不是说这个 Trigger 将不再触发了,而仅仅是当前 Trigger 的触发(并且紧接着的 Job 执行) 结束时。这个 Trigger 也许还要在将来触发多次的。
 
public class MyTriggerListener implements TriggerListener {

    @Override
    public String getName() {
        return "MyOtherTriggerListener";//这个不能返回null,必须填写;可以使用类的构造器传参的方法传入其他的Trigger监听器名称
    }

    /**
     * (1)
     * Trigger被激发 它关联的job即将被运行
     * Called by the Scheduler when a Trigger has fired, and it's associated JobDetail is about to be executed.
     */
    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext context) {
        System.out.println("MyOtherTriggerListener.triggerFired()");
    }

    /**
     * (2)
     * Trigger被激发 它关联的job即将被运行,先执行(1),在执行(2) 如果返回TRUE 那么任务job会被终止
     * Called by the Scheduler when a Trigger has fired, and it's associated JobDetail is about to be executed
     */
    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
        System.out.println("MyOtherTriggerListener.vetoJobExecution()");
        return false;
    }

    /**
     * (3) 当Trigger错过被激发时执行,比如当前时间有很多触发器都需要执行,但是线程池中的有效线程都在工作,
     *  那么有的触发器就有可能超时,错过这一轮的触发。
     * Called by the Scheduler when a Trigger has misfired.
     */
    @Override
    public void triggerMisfired(Trigger trigger) {
        System.out.println("MyOtherTriggerListener.triggerMisfired()");
    }

    /**
     * (4) 任务完成时触发
     * Called by the Scheduler when a Trigger has fired, it's associated JobDetail has been executed
     * and it's triggered(xx) method has been called.
     */
    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext context,
            CompletedExecutionInstruction triggerInstructionCode) {
        System.out.println("MyOtherTriggerListener.triggerComplete()");
    }

}

  

//向调度程序注册全局监听触发器

scheduler.getListenerManager().addTriggerListener(myTriggerListener, allTriggers());

//向调度程序注册一个指定的监听触发器

scheduler.getListenerManager().addTriggerListener(myTriggerListener, triggerKeyEquals(triggerKey("myTriggerName", "myTriggerGroup")));

//向调度程序注册一个特定组的触发器
scheduler.getListenerManager().addTriggerListener(myTriggerListener, triggerGroupEquals("myTriggerGroup"));

  

  (3)SchedulerListener

转载于:https://www.cnblogs.com/iapetosee/p/10886114.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值