quartz 学习笔记

StdScheduler 通过文件加载的方式初始化Schedule工厂
 
  // Create an instance of the factory  
  StdSchedulerFactory factory = new StdSchedulerFactory();  
 
  // Create the properties to configure the factory  
  Properties props = new Properties();  
 
  // required to supply threadpool class and num of threads  
 
  props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS,  
                    "org.quartz.simpl.SimpleThreadPool");  
 
  props.put("org.quartz.threadPool.threadCount", "10");  
   
  // Initialize the factory with properties  
  factory.initialize(props);
 
  Scheduler scheduler = factory.getScheduler();  
 
DirectSchedulerFactory通过硬编码的方式初始化Scheduler工厂

  DirectSchedulerFactory factory=DirectSchedulerFactory.getInstance();  
 
  // Initialize the Scheduler Factory with 10 threads  
  factory.createVolatileScheduler(10);  
 
  // Get a scheduler from the factory  
  Scheduler scheduler = factory.getScheduler();  
 
Scheduler生命周期中的方法
  scheduler.start();   开始
  scheduler.shutdonw(); 结束
  注意:别在 shutdown() 之后调用 start()
  Scheduler 实例被关闭之后你就不能调用它的 start() 方法了。这是因为 shutdown() 方法销毁了为  
  Scheduler 创建的所有的资源(线程,数据库连接等)。假如你在 shutdown() 之后调用 start()你将
  收到 SchedulerException 的异常。

org.quartz.Job 接口

  把 Quartz 作用到 Java 类上唯一要做的就是让它实现 org.quartz.Job 接口。你的 Job 类可以实现
  任何其他想要的接口或继承任何需要的基类,但是它自己或是它的超类必须实现这个 Job 接口。这个
  Job 接口只定义了单个方法:

   public void execute(JobExecutionContext context)  
     throws JobExecutionException; 

JobExecutionContext

   当 Scheduler 调用一个 Job,一个 JobexecutionContext 传递给 execute() 方法。        
   JobExecutionContext 对象让 Job 能访问 Quartz 运行时候环境和 Job 本身的明细数据。

JobDetail

  对于部署在 Scheduler 上的每一个 Job 只创建了一个 JobDetail 实例。JobDetail 是作为 Job 实
  例进行定义的

JobDataMap

  org.quartz.JobDataMap 来定义 Job 的状态。JobDataMap 通过它的超类 org.quartz.util.DirtyFlagMap
  实现了 java.util.Map 接口,你可以向 JobDataMap 中存入键/值对,那些数据对可在你的
  Job 类中传进行访问。这是一个向你的 Job 传送配置的信息便捷方法。
  // Every job has its own job detail  
  JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();  

使用有状态的 Job

  当你需要在两次 Job 执行间维护状态的话,Quartz 框架为此提供了 org.quartz.StatefulJob 接口。
  StatefulJob 接口仅仅是扩展了 Job 接口,未加入新的方法。你只需要通过使用与 Job 接口相同的
  execute() 方法简单的实现 StatefulJob 接口即可。假如你有已存在的 Job 类,你所有要做的只是
  改变 Job 的接口为 org.quartz.StatefulJob。

改变有状态 Job 的 JobDataMap

  你可以在有状态 Job 中简单的通过 map 的 put() 方法来修改 JobDataMap.已存在的任何数据会被新
  的数据覆盖掉。你也能对无状态的 Job 这么做,但是因为对于无状态 Job 来说,JobDataMap 不会持
  久化,所以数据不会保存下来。对于 Trigger 和 JobExecutionContext 上的 JobDataMap 的数据修改
  也是没能保存下来的。

Job 的易失性

  一个易失性的 Job 是在程序关闭之后不会被持久化。一个 Job 是通过调用 JobDetail 的
  setVolatility(true) 被设置为易失性的。
 
  当你需要持久化 Job 时不应使用 RamJobStore,RamJobStore 使用的是非永久性存储器,
  所有关于 Job 和 Trigger 的信息会在程序关闭之后丢失。保存 Job 到 RamJobStore 有效的使得它们
  是易失性的。假如你需要让你的 Job 信息在程序重启之后仍能保留下来,你就该考虑另一种 JobStore
  类型,比如 JobStoreTX 或者 JobStoreCMT。

Job 持久性

  一个持久的 Job 是它应该保持在  JobStore 中的,甚至是在没有任何 Trigger 去触发它的时候。我们
  说,你设置了一个单次触发的 Trigger,触发之后它就变成了 STATE_COMPLETE 状态。Job 执行一次后
  就不再被触发了,这个 Trigger 部署之后只为了执行一次。这个 Trigger 指向的 Job 现在成了一个
  孤儿 Job,因为不再有任何 Trigger 与之相关联了。

  假如你设置一个 Job 为连续性的,即使它成了孤儿 Job 也不会从 JobStore 移除掉。这样可以保证在
  将来,无论何时你的程序决定为这个 Job 增加另一个 Trigger 都是可用的。假如调用了 JobDetail 的
  setDurability(false) 方法,那么在所有的触发器触发之后 Job 将从 JobStore 中移出。连续性的默
  认值是 false。因此,Job 和 Trigger 的默认行为是:当 Trigger 完成了所有的触发、Job 在没有
  Trigger 与之关联时它们就会从 JobStore 中移除。

Job 的可恢复性

  当一个 Job 还在执行中,Scheduler 经历了一次非预期的关闭,在 Scheduler 重启之后可恢复的 Job
  还会再次被执行。这个 Job 会再次重头开始执行。Scheduler 是没法知道在程序停止的时候 Job 执行
  到了哪个位置,因此必须重新开始再执行一遍。要设置 Job 为可恢复性,用下面的方法:
  public void setRequestsRecovery(boolean shuldRecover);
  默认时,这个值为 false,Scheduler 不会试着去恢复 job 的。

Scheduler 中移除 Job

  多种方式移除已部署的 Job。一种方式是移除所有与这个 Job 相关联的 Trigger;如果这个 Job 是非持久
  性的,它将会从 Scheduler 中移出。一个更简单直接的方式是使用 deleteJob() 方法:

  public boolean deleteJob(String jobName, String groupName)throws SchedulerException; 

中断 Job

  Quartz 包括一个接口叫做 org.quartz.InterruptableJob,它扩展了普通的 Job 接口并提供了一个
  interrupt() 方法:

  public void interrupt() throws UnableToInterruptJobException;

  可以提供 Job 部署时所用的 Job 的名称和组名调用 Scheduler 的 interrupte() 方法:

  public boolean interrupt(SchedulingContext ctxt, String jobName, String groupName) throws 
  UnableToInterruptJobException; 

框架所提供的 Job

  org.quartz.jobs.FileScanJob 检查某个指定文件是否变化,并在文件被改变时通知到相应监听器的 Job
  org.quartz.jobs.FileScanListener 在文件被修改后通知 FileScanJob 的监听器 
  org.quartz.jobs.NativeJob 用来执行本地程序(如 windows 下 .exe 文件) 的 Job
  org.quartz.jobs.NoOpJob 什么也不做,但用来测试监听器不是很有用的。一些用户甚至仅仅用它来导致
  一个监听器的运行
  org.quartz.jobs.ee.mail.SendMailJob 使用 JavaMail API 发送 e-mail 的 Job
  org.quartz.jobs.ee.jmx.JMXInvokerJob 调用 JMX bean 上的方法的 Job
  org.quartz.jobs.ee.ejb.EJBInvokerJob 用来调用 EJB 上方法的 Job

主处理线程:QuartzSchedulerThread

  Quartz 应用第一次运行时,main 线程会启动 Scheduler。QuartzScheduler 被创建并创建一个
  org.quartz.core.QuartzSchedulerThread 类的实例。QuartzSchedulerThread 包含有决定何时下一个
  Job 将被触发的处理循环。顾名思义,QuartzSchedulerThread 是一个 Java 线程。它作为一个非守护线
  程运行在正常优先级下。


QuartzSchedulerThread 的主处理循环的职责描述如下:

1. 当 Scheduler 正在运行时:

    A. 检查是否有转换为 standby 模式的请求。

       1. 假如 standby 方法被调用,等待继续的信号

    B. 询问 JobStore 下次要被触发的 Trigger.

       1. 如果没有 Trigger 待触发,等候一小段时间后再次检查

2. 假如有一个可用的 Trigger,等待触发它的确切时间的到来

    D. 时间到了,为 Trigger 获取到 triggerFiredBundle.

    E. 使用 Scheduler 和 triggerFiredBundle 为 Job 创建一个 JobRunShell 实例

    F. 告诉 ThreadPool 可能时运行 JobRunShell.

    这个逻辑存在于 QuartzSchedulerThread 的 run() 方法中。

QuartzSchedulerResources

  当工厂创建 Scheduler 实例时,它还会传递给 Scheduler 一个 org.quartz.core.QuartzSchedulerResoures
  实例。QuartzSchedulerResourecs 除包含以上东西之后,还有一个 ThreadPool 实例,它提供了一个工作者
  线程池来负责执行 Job。在 Quartz 中,ThreadPool 是由 org.quartz.spi.ThreadPool 接口 (因为 Quartz
  是在 JDK 1.5 之前产生的,所以需要自己的 ThreadPool 类确保向后的兼容性,Quartz   仍然用自己的
  ThreadPool 替代 Java 的) 表示的,并提供一个名为 org.quartz.simp.SimpleThreadPool 的具体实现类。
  SimpleThreadPool 有一个固定数目的工作者线程,在加载之后就不再减少或增多

Quartz 工作者线程

  Quartz 不会在 main 线程中处理你的 Job。如果这么做,会严重降低应用的可扩展性。相应的,Quartz
  把线程管理的职责委托给分散的组件。对于一般的 Quartz 设置 (这部分还是很费功夫的),都是用
  SimpleThreadPool  类处理线程的管理。SimpleThreadPool 创建了一定数量的 WorkerThread 实例来使得
  Job 能够在分散的线程中进行处理。WorkerThread 是定义在 SimpleThreadPool 类中的内部类,它实质上就是
  一个线程。要创建 WorkerThread 的数量以及为他们的优先级是配置在文件 quartz.properties 中并传入工厂的

JobRunShell 的 run() 方法

  虽然 WorkerThread 是真正的 Java 线程,JobRunShell 类也还是实现了 Runable。那意味着它可以作为一个
  线程并包含一个 run() 方法。在本章前面讨论过,JobRunShell 的目的是调用 Job 的 execute() 方法。
  不仅如此,它还要负责通知 Job 和 Trigger 监听器,在运行完成后还得更新此次执行的 Trigger 的信息。

org.quartz.SimpleTrigger

  正如其名所示,SimpleTrigger 对于设置和使用是最为简单的一种 Quartz Trigger。它是为那种需要在特定
  的日期/时间启动,且以一个可能的间隔时间重复执行 n  次的 Job 所设计的。

org.quartz.CronTrigger

  CronTrigger 允许设定非常复杂的触发时间表,顾名思义,CronTrigger 是基于 Unix 类似于 cron 的表达式。

org.quartz.NthIncludedDayTrigger
 
  它设计用于在每一间隔类型的第几天执行 Job。Quartz 的 Caldendar 也可与 Trigger 关联以此把周末与
  节假日考虑进来,并在必要时跳开这些日期。

为一个 Job 使用多个 Trigger

  单个 JobDetail 能够支持多个 Trigger,但一个 Trigger 只能被指派给一个 Job。

org.quartz.Calendar

  Quartz 定义了 org.quartz.Calendar 接口,所有的 Quartz Calendar 必须实现它。它包含了几个方法,
  但是有两个是最重要的:

  public long getNextIncludedTime(long timeStamp);  
  public boolean isTimeIncluded(long timeStamp);

作为一个 Quartz Job 的创建者和开发者,你可不必去熟悉 Calender 接口。这主要是因为已有的 Calendar
(Quartz 自带的) 需要应付的情况就不够多。开箱即用的,Quartz 包括许多的 Calender 实现足以满足你的要求

  org.quartz.impl.calendar.BaseCalender 为高级的 Calender 实现了基本的功能,实现了
  org.quartz.Calender 接口
  org.quartz.impl.calendar.WeeklyCalendar 排除星期中的一天或多天,例如,可用于排除周末
  org.quartz.impl.calendar.MonthlyCalendar 排除月份中的数天,例如,可用于排除每月的最后一天
  org.quartz.impl.calendar.AnnualCalendar  排除年中一天或多天
  org.quartz.impl.calendar.HolidayCalendar 特别的用于从 Trigger 中排除节假日

Calendar examle
 
 // Create an instance of the Quartz AnnualCalendar  
        AnnualCalendar cal = new AnnualCalendar();  
 
        // exclude July 4th  
        Calendar gCal = GregorianCalendar.getInstance();  
        gCal.set(Calendar.MONTH, Calendar.JULY);  
        gCal.set(Calendar.DATE, 4);  
 
        cal.setDayExcluded(gCal, true);  
 
        // Add to scheduler, replace existing, update triggers  
        scheduler.addCalendar("bankHolidays", cal, true, true);
       
  /* 
          * Set up a trigger to start firing now, repeat forever 
          * and have (60000 ms) between each firing. 
         */ 
        Trigger trigger = TriggerUtils.makeImmediateTrigger("myTrigger",  -1,60000);  

        trigger.setCalendarName("bankHolidays");  
       
        //HolidayCalender 类考虑的是年份。因此,如果你希望在后续三年中排除 7 月 4 日,
        //你需要把三年中的每个日期都作为要排除的项。而 AnnualCalender 可简单的为每年
        //设定要排除的日期

CronTrigger 使用起迄日期

  CronTrigger 的 setStartTime() 和 setEndTime() 方法来形成一个 "定时箱" 来触发。

JobStore 接口

  Quartz 为所有类型的 Job 存储提供了一个接口。这个接口位于 org.quartz.spi 包中,叫做
  JobStore。所有的 Job 存储机制,不管是在哪里或是如何存储他们的信息的,都必须实现这个接口。

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值