Quartz - Calendar

不要混淆了 Quartz 的 Calendar 对象与 Java API 的 java.util.Calendar。它们是应用于不同目的不一样的组件。正如你大概所知,Java 的 Calender 对象是通用的日期和时间工具;许多过去由 Java 的 Date 类提供的功能现在加到了 Calendar 类中了。另一方面,Quartz 的 Calender 专门用于屏闭一个时间区间,使 Trigger 在这个区间中不被触发。例如,让我们假如你是为一个财务机构(如银行)工作。对于银行普遍的都有许多 "银行节日"。假设你不需要(或不想) Job 在那些日子里运行。你可以采用以下几种方法中的一种来实现:

  • 让你的 Job 总是运行。(这会让银行一团糟)
  • 在节假日期间手动停止你的 Job。(需要专门的人来负责做这个事情)
  • 创建不包含这些日子的多个 Trigger。(这对于设置和维护会较耗时的)
  • 设立一个排除这些日子的银行节日的 Calendar。(很轻松的实现)

虽然你可以用其中的一个方法来解决这样的问题,Quartz 的 Calender 却是特意为此而设计的。


org.quartz.Calender 接口

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

  1. public long getNextIncludedTime(long timeStamp);   
  2. public boolean isTimeIncluded(long timeStamp);  
public long getNextIncludedTime(long timeStamp);public boolean isTimeIncluded(long timeStamp);

Calender 排除时间的粒度:
Calendar 接口方法参数的类型是 Long。这说明 Quartz Calender 能够排除的时间细致毫秒级。你很可能永远都不需要这么细小的位度,因为大部分的 Job 只需要排除特别的日期或许会是小时。然而,假如你真需要排除到毫秒一级的,Calender 能帮你做到。

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

表 4.1. Quartz 包含了你的应用可用的许多的 Calender 类型
Calender 名称 用法
BaseCalender org.quartz.impl.calendar.BaseCalender 为高级的 Calender 实现了基本的功能,实现了 org.quartz.Calender 接口

WeeklyCalendar

org.quartz.impl.calendar.WeeklyCalendar

排除星期中的一天或多天,例如,可用于排除周末

MonthlyCalendar

org.quartz.impl.calendar.MonthlyCalendar

排除月份中的数天,例如,可用于排除每月的最后一天

AnnualCalendar

org.quartz.impl.calendar.AnnualCalendar

排除年中一天或多天

HolidayCalendar

org.quartz.impl.calendar.HolidayCalendar

特别的用于从 Trigger 中排除节假日


使用 Quartz 的 Calendar

要使用 Quartz Calendar,你只需简单的实例化,并加入你要排除的日期,然后用 Scheduler 注册它。最后把这个 Calender 实例与你想要使用该 Calender 的每一个 Trigger 实例关联起来。


多个 Job 共同一个 Calendar
你不能仅仅是把 Calendar 加入到 Scheduler 来为所有 Job 安排 Calendar。你需让 Calendar 实例关联到每一个 Trigger。Calender 实例被加到 Scheduler 中后,它只允许由使用中的
JobStore 存储;你必须让 Calender 依附于 Trigger 实例。


代码 4.10 显示的是一个使用 Quartz
AnnualCalender 类执行银行节日的例子。

代码 4.10. 使用 AnnualCalender 来排除银行节日

  1. public class Listing_4_10 {   
  2.      static Log logger = LogFactory.getLog(Listing_4_10.class);   
  3.   
  4.      public static void main(String[] args) {   
  5.           Listing_4_10 example = new Listing_4_10();   
  6.           example.startScheduler();   
  7.      }   
  8.   
  9.      public void startScheduler() {   
  10.           try {   
  11.               // Create and start the scheduler   
  12.               Scheduler scheduler =   
  13.                              StdSchedulerFactory.getDefaultScheduler();   
  14.               scheduler.start();   
  15.   
  16.               scheduleJob(scheduler, PrintInfoJob.class);   
  17.   
  18.               logger.info("Scheduler starting up...");   
  19.               scheduler.start();   
  20.   
  21.          } catch (SchedulerException ex) {   
  22.               logger.error(ex);   
  23.          }   
  24.     }   
  25.   
  26.     private void scheduleJob(Scheduler scheduler, Class jobClass) {   
  27.          try {   
  28.               // Create an instance of the Quartz AnnualCalendar   
  29.               AnnualCalendar cal = new AnnualCalendar();   
  30.   
  31.               // exclude July 4th   
  32.               Calendar gCal = GregorianCalendar.getInstance();   
  33.               gCal.set(Calendar.MONTH, Calendar.JULY);   
  34.               gCal.set(Calendar.DATE, 4);   
  35.   
  36.               cal.setDayExcluded(gCal, true);   
  37.   
  38.               // Add to scheduler, replace existing, update triggers   
  39.               scheduler.   
  40.                              addCalendar("bankHolidays", cal, truetrue);   
  41.   
  42.               /*  
  43.                        * Set up a trigger to start firing now, repeat forever  
  44.                        * and have (60000 ms) between each firing.  
  45.                */  
  46.               Trigger trigger =   
  47.                              TriggerUtils.makeImmediateTrigger("myTrigger",   
  48.                      -1,60000);   
  49.   
  50.               // Trigger will use Calendar to exclude firing times   
  51.               trigger.setCalendarName("bankHolidays");   
  52.   
  53.               JobDetail jobDetail =   
  54.                              new JobDetail(jobClass.getName(),   
  55.                         Scheduler.DEFAULT_GROUP, jobClass);   
  56.   
  57.               // Associate the trigger with the job in the scheduler   
  58.               scheduler.scheduleJob(jobDetail, trigger);   
  59.   
  60.          } catch (SchedulerException ex) {   
  61.               logger.error(ex);   
  62.          }   
  63.     }   
  64. }  

当你运行代码 4.10 中的例子时,除 7 月 4 号之外,你都可以看到 Job 会执行。作为一个留下来给你做的练习,在方法
scheduleJob() 中改变被排除的日期为你当前的日期。假如你再次跑这段代码,你将会看到当前日期被排除了,下次被触发的时间会是明天了。

为什么我们不用 HolidayCalender ?
你也许会有所疑惑,为什么我们在上个例子中不选择使用
HolidayCalender 呢?HolidayCalender 类考虑的是年份。因此,如果你希望在后续三年中排除 7 月 4 日,你需要把三年中的每个日期都作为要排除的项。而 AnnualCalender 可简单的为每年设定要排除的日期,也就更容易的应用于这种情况

创建你自己的 Calender

这最后一节演示了创建你自己的 Calender 类是多么的容易。假定你需要一个 Calender 去排除小时当中的某分钟。例如,假定你需要排除每小时中的前 5 分钟或者后 15 分钟。你能创建一个新的 Calender 来支持这种功能。

我们也许可以使用 CronTrigger
我们也许可以写出一个 Cron 表达式来排除这些时间,但那样就没了创建一个新
Calender 的乐趣了。

代码 4.11 是
HourlyCalender ,我们能用它让排除小时中的一些分钟。

代码 4.11. HourlyCalender 能从每小中排除某些分钟

  1. public class HourlyCalendar extends BaseCalendar {   
  2.   
  3.      // Array of Integer from 0 to 59   
  4.      private List excludedMinutes = new ArrayList();   
  5.   
  6.      public HourlyCalendar() {   
  7.           super();   
  8.      }   
  9.      public HourlyCalendar(Calendar baseCalendar) {   
  10.           super(baseCalendar);   
  11.      }   
  12.   
  13.      public List getMinutesExcluded() {   
  14.           return excludedMinutes;   
  15.      }   
  16.   
  17.      public boolean isMinuteExcluded(int minute) {   
  18.   
  19.           Iterator iter = excludedMinutes.iterator();   
  20.           while (iter.hasNext()) {   
  21.                Integer excludedMin = (Integer) iter.next();   
  22.   
  23.                if (minute == excludedMin.intValue()) {   
  24.                     return true;   
  25.                }   
  26.   
  27.                continue;   
  28.           }   
  29.           return false;   
  30.      }   
  31.   
  32.      public void setMinutesExcluded(List minutes) {   
  33.           if (minutes == null)   
  34.                return;   
  35.   
  36.           excludedMinutes.addAll(minutes);   
  37.      }   
  38.   
  39.      public void setMinuteExcluded(int minute) {   
  40.   
  41.           if (isMinuteExcluded(minute))   
  42.                return;   
  43.   
  44.           excludedMinutes.add(new Integer(minute));   
  45.      }   
  46.   
  47.      public boolean isTimeIncluded(long timeStamp) {   
  48.   
  49.           if (super.isTimeIncluded(timeStamp) == false) {   
  50.                return false;   
  51.           }   
  52.   
  53.           java.util.Calendar cal = getJavaCalendar(timeStamp);   
  54.           int minute = cal.get(java.util.Calendar.MINUTE);   
  55.   
  56.           return !(isMinuteExcluded(minute));   
  57.      }   
  58.   
  59.      public long getNextIncludedTime(long timeStamp) {   
  60.           // Call base calendar implementation first   
  61.           long baseTime = super.getNextIncludedTime(timeStamp);   
  62.           if ((baseTime > 0) && (baseTime > timeStamp))   
  63.               timeStamp = baseTime;   
  64.   
  65.           // Get timestamp for 00:00:00   
  66.           long newTimeStamp = buildHoliday(timeStamp);   
  67.           java.util.Calendar cal = getJavaCalendar(newTimeStamp);   
  68.           int minute = cal.get(java.util.Calendar.MINUTE);   
  69.   
  70.           if (isMinuteExcluded(minute) == false)   
  71.                return timeStamp; // return the   
  72.           // original value   
  73.   
  74.           while (isMinuteExcluded(minute) == true) {   
  75.                cal.add(java.util.Calendar.MINUTE, 1);   
  76.           }   
  77.           return cal.getTime().getTime();   
  78.     }   
  79. }  

如果你使用
HourlyCalender 去部署 Job,需要你做的事情是设置小时中你希望排除的分钟;由 Calender 和 Scheduler 做剩下的事情。你能看到在代码 4.12 中对  HourlyCalender 的演示。

 
代码 4.12. HourlyCalender 基于小时中排除某些分钟来执行

  1. public class Listing_4_12 {   
  2.      static Log logger = LogFactory.getLog(Listing_4_12.class);   
  3.   
  4.      public static void main(String[] args) {   
  5.           Listing_4_12 example = new Listing_4_12();   
  6.           example.startScheduler();   
  7.      }   
  8.   
  9.      public void startScheduler() {   
  10.           try {   
  11.                // Create a default instance of the Scheduler   
  12.                Scheduler scheduler =   
  13.                         StdSchedulerFactory.getDefaultScheduler();   
  14.   
  15.                // Using the NoOpJob, but could have been any   
  16.                scheduleJob(scheduler, PrintInfoJob.class);   
  17.   
  18.                logger.info("Scheduler starting up...");   
  19.                scheduler.start();   
  20.   
  21.           } catch (SchedulerException ex) {   
  22.                logger.error(ex);   
  23.           }   
  24.      }   
  25.   
  26.      private void scheduleJob(Scheduler scheduler, Class jobClass) {   
  27.           try {   
  28.                // Create an instance of the Quartz AnnualCalendar   
  29.                HourlyCalendar cal = new HourlyCalendar();   
  30.                cal.setMinuteExcluded(47);   
  31.                cal.setMinuteExcluded(48);   
  32.                cal.setMinuteExcluded(49);   
  33.                cal.setMinuteExcluded(50);   
  34.   
  35.                // Add Calendar to the Scheduler   
  36.                scheduler.   
  37.                          addCalendar("hourlyExample", cal, truetrue);   
  38.   
  39.                Trigger trigger =   
  40.                          TriggerUtils.makeImmediateTrigger("myTrigger",   
  41.                          -110000);   
  42.   
  43.                // Trigger will use Calendar to exclude firing times   
  44.                trigger.setCalendarName("hourlyExample");   
  45.   
  46.                JobDetail jobDetail =   
  47.                          new JobDetail(jobClass.getName(),   
  48.                          Scheduler.DEFAULT_GROUP, jobClass);   
  49.   
  50.                // Associate the trigger with the job in the scheduler   
  51.                scheduler.scheduleJob(jobDetail, trigger);   
  52.   
  53.           } catch (SchedulerException ex) {   
  54.                logger.error(ex);   
  55.           }   
  56.      }   
  57.  }  

当你运行 4.12 中的代码,你会看到
PrintInfoJob 在被排除的分钟是不被执行,在方法 setMinuteExcluded() 方法中依你要求改变需排除的分钟,来看看新的 Calender 是如何工作的。

你可能感兴趣的:(Quartz - Calendar)