Quartz学习(2)

4.更多关于Triggers

 

jobs一样,triggers也相对来说很容易。但是,我们还是要理解它的一些特性。Quartz

 

也有很多类型的trigger提供给我们使用。

 

Calendars

 

Quartz Calendar 对象(不是java.util.Calendar对象)能够在trigger储存在调度器时和trigger

 

关联起来。Calendars主要用来在trigger配置时排除一些时间。例如,你能够创建一个在每

 

个工作日早上930触发的trigger,然后为这个trigger增加一个排除所有商业的节假日的

 

Calendar

 

Calendars能够是任何序列化的对象,只要这些对象实现了Calendar接口:

 

package org.quartz;

 

  public interface Calendar {

 

    public boolean isTimeIncluded(long timeStamp);

 

    public long getNextIncludedTime(long timeStamp);

 

  }

 

注意到这些方法的参数类型是long。这意味着calendars能够排除毫秒级的时间段。大部分

 

地,我们感兴趣的是一整天的,所以在Quartz里,有个实现类提供了方便:

 

org.quartz.impl.HolidayCalendar

 

Calendars必须被实例化并且通过addCalendar(..)方法注册到调度器里。如果你用

 

HolidayCalendar,在实例它之后,你应该用它的addExcludedDate(Date date)方法以便组装上

 

你想排除的那几天。一个calendar实例能够被多个triggers使用:

 

HolidayCalendar cal new HolidayCalendar();

 

  cal.addExcludedDate( someDate );

 

  sched.addCalendar("myHolidays", cal, false);

 

  Trigger trigger TriggerUtils.makeHourlyTrigger(); // 每小时触发

 

  trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));  //下一个小时

 

开始 trigger.setName("myTrigger1");

 

  trigger.setCalendarName("myHolidays");

 

  // .. schedule job with trigger

 

  Trigger trigger2 TriggerUtils.makeDailyTrigger(8, 0); // 每天早上8点触发

 

  trigger2.setStartTime(new Date()); //立即开始

 

  trigger2.setName("myTrigger2");

 

  trigger2.setCalendarName("myHolidays");

 

  // .. schedule job with trigger2

 

不触发(misfire)指令

 

触发器的另外一个重要的属性是“不触发指令”。如果一个持久的触发器由于调

 

度器被关闭了而没有找到它的触发时间,那么一个不触发将会发生。不同的触发

 

器类型有不同的不触发指令。默认的,他们都用“smart policy”指令-这是一个

 

基于触发器类型和配置的动态行为。当调度器启动时,他将会搜寻所有没触发的

 

持久化的triggers,然后基于他们各个配置的不触发指令来更新他们。当你用

 

Quartz,你应该熟悉各个不触发指令,我们在以下章节有一些介绍。给一个trigger

 

实例配置不触发指令,要用此实例的setMisfireInstruction(..)方法。

 

TriggerUtils Triggers Made Easy

 

TriggerUtils类(在org.quartz包里)包含了很多方便的工具。能够帮你创建triggersdatas

 

用这个类能够很容易制造一些trigges,这些triggers能够在每分钟,每小时,每周,每个月

 

等等触发。用它也能产生一些接近某个秒、分钟、小时的天-这在设置trigger的启动时间很

 

有帮助。

 

TriggerListeners

 

最后,triggers有一些注册了的监听器,象job一样。实现了TriggerListener接口的

 

对象将接受一个trigger被触发的通知。

 

5. SimpleTrigger

 

详细介绍一下它的构造器:

 

public SimpleTrigger(String name, //trigger名称

 

                  String group, //trigger的组名

 

                  Date startTime, //开始时间

 

                  Date endTime, //结束时间

 

                   int repeatCount, //重复次数

 

                   long repeatInterval)//重复间隔

 

举几个常用例子:

 

从现在开始10秒后执行一次:

 

long startTime System.currentTimeMillis() 10000L;

 

  SimpleTrigger trigger new SimpleTrigger("myTrigger",

 

                                            null,

 

                                            new Date(startTime),

 

                                            null,

 

                                            0,

 

0L);

 

立即执行,60秒间隔无限制重复:

 

SimpleTrigger trigger new SimpleTrigger("myTrigger",

 

                                            null,

 

                                            new Date(),

 

                                            null,

 

                                            SimpleTrigger.REPEAT_INDEFINITELY,

 

60L 1000L);

 

从现在开始立即执行,每10秒重复,直到40秒后:

 

long endTime System.currentTimeMillis() 40000L;

 

  SimpleTrigger trigger new SimpleTrigger("myTrigger",

 

                                            "myGroup",

 

                                            new Date(),

 

                                            new Date(endTime),

 

                                            SimpleTrigger.REPEAT_INDEFINITELY,

 

10L 1000L);

 

20023171030am触发,重复5次(一共6次),30秒间隔:

 

java.util.Calendar cal new java.util.GregorianCalendar(2002, cal.MARCH, 17);

 

  cal.set(cal.HOUR, 10);

 

  cal.set(cal.MINUTE, 30);

 

  cal.set(cal.SECOND, 0);

 

  cal.set(cal.MILLISECOND, 0);

 

  Data startTime cal.getTime();

 

  SimpleTrigger trigger new SimpleTrigger("myTrigger",

 

                                            null,

 

                                            startTime,

 

                                            null,

 

                                            5,

 

                                            30L 1000L);

 

SimpleTrigger 不触发指令

 

MISFIRE_INSTRUCTION_FIRE_NOW

 

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_C

 

OUNT

 

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT

 

_COUNT

 

MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT

 

MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

 

6.CronTrigger

 

构造器

 

CronTrigger(String name, //触发器名称

 

String group, //触发器的组名

 

String jobName, //job名称

 

String jobGroup, //job的组名

 

Date startTime, //开始时间

 

Date endTime, //结束时间

 

String cronExpression, //克隆表达式

 

TimeZone timeZone)//时区

 

还有一些其它参数少一些的构造器,参考JavaDoc。通常我们如下简单地使用

 

CronTrigger

 

Trigger trigger new CronTrigger("trigger1", "group1");//设置触发器名称和组名

 

trigger.setCronexpression_r("0 15 ?");//设置克隆表达式

 

克隆表达式

 

一个克隆表达式是一个由空白间隔6个或者7个字段的字符串。

 

格式:

 

字段名

必须有?

值范围

允许的特殊字符

Seconds

YES

0-59

/

Minutes

YES

0-59

/

Hours

YES

0-23

/

Day of month

YES

1-31

C

Month

YES

1-12 or JAN-DEC

/

Day of week

YES

1-7 or SUN-SAT

#

Year

NO

empty, 1970-2099

/

例子:

 

*

 

0/5 14,18,3-39,52 JAN,MAR,SEP MON-FRI 2002-2010

 

特殊字符

 

* 表示所有值 

 

? 表示未说明的值,即不关心它为何值;

 

- 表示一个指定的范围;

 

, 表示附加一个可能值;

 

/ 符号前表示开始时间,符号后表示每次递增的值;

 

L ("last""L" 用在day-of-month字段意思是 "这个月最后一天";用在 

 

day-of-week字段它简单意思是 "7" or "SAT" 如果在day-of-week字段里

 

和数字联合使用,它的意思就是 "这个月的最后一个星期几" – 例如: "6L" 

 

means "这个月的最后一个星期五"当我们用“L”时,不指明一个列表值或

 

者范围是很重要的,不然的话,我们会得到一些意想不到的结果。

 

W ("weekday"只能用在day-of-month字段。用来描叙最接近指定天的工

 

作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个

 

月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个

 

月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月

 

16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。

 

注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅

 

能在day-of-month指明一天,不能是一个范围或列表。

 

也可以用“LW”来指定这个月的最后一个工作日。

 

# -只能用在day-of-week字段。用来指定这个月的第几个周几。例:在

 

day-of-week字段用"6#3"指这个月第3个周五(6指周五,3指第3个)。如果指

 

定的日期不存在,触发器就不会触发。

 

C ("calendar"– 指和calendar联系后计算过的值。例:在day-of-month 

 

段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week

 

字段用“1C”指在这周日或之后包括calendar的第一天。

 

MONTHDay of week字段里对字母大小写不敏感。

 

一些例子

 

表达式

意思(触发时刻)

12 ?

每天中午12点

15 10 2005

在2005年的每天10:25

10,44 14 WED

在3月里每个周三的14:10和14:44

15 10 6L 2002-2005

从2002年到2005年里,每个月的最后一个星期五的10:15

12 1/5 ?

从当月的第一天开始,然后在每个月每隔5天的12:00

15 10 6#3

每个月第3个周五的10:15

注意在day-of-weekday-of-month字段里使用“?”和“*”的效果。

 

注意

 

对“C”的支持并不很完全。

 

对在day-of-week字段 和在day-of-month字段同时使用也不是很完全(目

 

前你必须在这两个字段中的一个用“?”指定)。

 

当设置在午夜和凌晨1点之间触发时要仔细。

 

不触发指令:

 

MISFIRE_INSTRUCTION_FIRE_ONCE_NOW

 

MISFIRE_INSTRUCTION_DO_NOTHING

 

7.TriggerListeners JobListeners

 

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);

 

}

 

job相关的事件有:job准备执行,job执行完毕。

 

public interface JobListener {

 

    public String getName();

 

    public void jobToBeExecuted(JobExecutionContext context);

 

    public void jobExecutionVetoed(JobExecutionContext context);

 

    public void jobWasExecuted(JobExecutionContext context,

 

                                        JobExecutionException 

 

jobException);

 

}

 

使用Listeners

 

创建一个监听器,就是创建一个实现了org.quartz.TriggerListener  

 

org.quartz.JobListener接口的对象。在运行的期间用调度器注册监听器,必须要

 

给它提供一个名字。监听器能够注册成为全局的或者不是全局的,全局监听器接

 

受所有的事件,而非全局的则仅接受指定给triggers/jobs了的事件。

 

监听器是在运行期间被调度器注册的,他们没有伴随jobstriggers储存在JobStore里。Jobs

 

triggers仅储存和它们相关的监听器的名字。因此,每次程序运行时,监听器需要被调度

 

器再次注册。

 

scheduler.addGlobalJobListener(myJobListener);

 

scheduler.addJobListener(myJobListener);

 

监听器在Quartz并不是经常使用的。

 

8.SchedulerListeners

 

和调度器相关的事件有:job/trigger的加入和移出,一些调度器里的错误,调度

 

器关闭等等。

 

public interface SchedulerListener {

 

    public void jobScheduled(Trigger trigger);

 

    public void jobUnscheduled(String triggerName, String triggerGroup);

 

    public void triggerFinalized(Trigger trigger);

 

    public void triggersPaused(String triggerName, String triggerGroup);

 

    public void triggersResumed(String triggerName, String triggerGroup);

 

    public void jobsPaused(String jobName, String jobGroup);

 

    public void jobsResumed(String jobName, String jobGroup);

 

    public void schedulerError(String msg, SchedulerException cause);

 

    public void schedulerShutdown();

 

}

 

创建和注册SchedulerListeners和其他监听器一样,全局和非全局的没有区别。

 

9.JobStores

 

JobStore负责保存所有配置到调度器里的工作数据:jobstriggerscalendars等等。在用

 

SchedulerFactory得到一个调度器的实例时,我们可以给SchedulerFactory提供一个属性文件

 

或者一个属性对象来声明使用哪个JobStore

 

注意,不要在代码里使用JobStore的实例,这些Quartz都做好了。我们要做的就仅仅告诉

 

Quartz(通过配置)用哪个JobStore,然后就调用Scheduler接口函数了。

 

RAMJobStore

 

利用内存来持久化调度程序信息。这种作业存储类型最容易配置、构造和运行,

 

但是当应用程序停止运行时,所有调度信息将被丢失。

 

在属性文件里指定:

 

org.quartz.jobStore.class org.quartz.simpl.RAMJobStore

 

JDBCJobStore

 

支持的数据库有:Oracle, MySQL, MS SQLServer2000, HSQLDB, PostreSQL and 

 

DB2。使用JDBCJobStore,首先要在数据库里建一些Quartz要使用的表。我们

 

可以使用Quartz发布包里的建表脚本,在docs/dbTables目录下。如果没有你所

 

要的数据库类型的脚本,可以在已有的脚本作一些修改。所有这些标都是以

 

QRTZ_”作为前缀的,这个前缀是可以在属性文件里更改的。在为多个调度器

 

实例创建多个系列的表时,用不同的前缀是很有用的。

 

一旦我们创建了这些表,在配置和触发JDBCJobStore之前就要做更多的事

 

情了。我们需要决定应用需要哪种类型的事务处理。如果我们不需要给其他的事

 

务处理一些调度命令(增加删除trigger),我们就可以让Quartz利用JobStoreTX

 

处理这个事务(这用的很多)。

 

如果我们需要Quartz和其他的事务处理(在J2EE应用服务器里)一起工作,

 

我们就应该用JobStoreCMT-这会使Quartz让应用服务器容器管理事务。

 

最后一点是从哪个JDBCJobStore启动数据库能够得到该数据库的连接。在

 

属性文件里是用一个不同的方法来定义数据源的。一种是Quartz自己创建和管

 

理数据源-提供所有的数据库连接信息;另外一种是利用应用服务器管理的数据

 

源,其中Quartz运行在这个应用服务器里-JDBCJobStore提供数据库的JNDI

 

名称。

 

JDBCJobStore(假设我们是用的StdSchedulerFactory),我们首先要设置

 

org.quartz.jobStore.class属性为org.quartz.impl.jdbcjobstore.JobStoreTX或者

 

org.quartz.impl.jdbcjobstore.JobStoreCMT,这取决于我们的选择。

 

org.quartz.jobStore.class org.quartz.impl.jdbcjobstore.JobStoreTX

 

下一步,我们需要选择一个驱动代理。StdJDBCDelegate是一个用

 

vanillaJDBC代码实现的代理。如果没有其他为你数据库指定的代理,就使

 

用这个。Quartz开发者们解决的问题都是根据这个代理的来实现的。其他的代理

 

org.quartz.impl.jdbcjobstore包或者子包里。包括DB2v6DelegateDB2 version 

 

或早期版本使用的),HSQLDBDelegateHSQLDB使用),MSSQLDelegate

 

microsoft SQLServer 2000使用),PostgreSQLDelegatePostgreSQL 7.x使用),

 

WeblogicDelegateWeblogicJDBC驱动器使用),OracleDelegateOracle 8i and 

 

9i使用)。

 

org.quartz.jobStore.driverDelegateClass org.quartz.impl.jdbcjobstore.StdJDBCDelegate

 

在下一步,我们要配置表的前缀:

 

org.quartz.jobStore.tablePrefix QRTZ_

 

最后,我们需要设置用哪个数据源,数据源的名称必须在Quartz属性里定义好。

 

例如,我们可以给Quartz指定使用“myDS”(在配置属性里的其他地方定义好

 

了)作为数据源的名字。

 

org.quartz.jobStore.dataSource myDS

 

如果调度器很繁忙(例如,执行job的个数和线程池的大小一样),那么我们应

 

该设置数据源的连接个数在线程池大小+1之上。

 

org.quartz.jobStore.useProperties这个属性能够设置为“true”(默认为false),

 

用来指示JDBCJobStore:在JobDataMaps里的所有值都应该是String,这样在能

 

作为name-value方式储存,而不是在BLOB列里以序列化的格式储存复杂的对

 

象。从长远看,这样做会很安全,因为你可以避免将非String的类序列化到BLOB

 

里的类版本问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ma_xs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值