4.更多关于Triggers
象jobs一样,triggers也相对来说很容易。但是,我们还是要理解它的一些特性。Quartz里
也有很多类型的trigger提供给我们使用。
Calendars
Quartz
关联起来。Calendars主要用来在trigger配置时排除一些时间。例如,你能够创建一个在每
个工作日早上9:30触发的trigger,然后为这个trigger增加一个排除所有商业的节假日的
Calendar。
Calendars能够是任何序列化的对象,只要这些对象实现了Calendar接口:
package
注意到这些方法的参数类型是long。这意味着calendars能够排除毫秒级的时间段。大部分
地,我们感兴趣的是一整天的,所以在Quartz里,有个实现类提供了方便:
org.quartz.impl.HolidayCalendar
Calendars必须被实例化并且通过addCalendar(..)方法注册到调度器里。如果你用
HolidayCalendar,在实例它之后,你应该用它的addExcludedDate(Date
你想排除的那几天。一个calendar实例能够被多个triggers使用:
HolidayCalendar
开始
不触发(misfire)指令
触发器的另外一个重要的属性是“不触发指令”。如果一个持久的触发器由于调
度器被关闭了而没有找到它的触发时间,那么一个不触发将会发生。不同的触发
器类型有不同的不触发指令。默认的,他们都用“smart
基于触发器类型和配置的动态行为。当调度器启动时,他将会搜寻所有没触发的
持久化的triggers,然后基于他们各个配置的不触发指令来更新他们。当你用
Quartz,你应该熟悉各个不触发指令,我们在以下章节有一些介绍。给一个trigger
实例配置不触发指令,要用此实例的setMisfireInstruction(..)方法。
TriggerUtils
TriggerUtils类(在org.quartz包里)包含了很多方便的工具。能够帮你创建triggers和datas。
用这个类能够很容易制造一些trigges,这些triggers能够在每分钟,每小时,每周,每个月
等等触发。用它也能产生一些接近某个秒、分钟、小时的天-这在设置trigger的启动时间很
有帮助。
TriggerListeners
最后,triggers有一些注册了的监听器,象job一样。实现了TriggerListener接口的
对象将接受一个trigger被触发的通知。
5.
详细介绍一下它的构造器:
public
举几个常用例子:
从现在开始10秒后执行一次:
long
0L);
立即执行,60秒间隔无限制重复:
SimpleTrigger
60L
从现在开始立即执行,每10秒重复,直到40秒后:
long
10L
在2002年3月17号10:30am触发,重复5次(一共6次),30秒间隔:
java.util.Calendar
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
String
String
String
Date
Date
String
TimeZone
还有一些其它参数少一些的构造器,参考JavaDoc。通常我们如下简单地使用
CronTrigger;
Trigger
trigger.setCronexpression_r("0
克隆表达式
一个克隆表达式是一个由空白间隔6个或者7个字段的字符串。
格式:
字段名
必须有?
值范围
允许的特殊字符
Seconds
YES
0-59
,
Minutes
YES
0-59
,
Hours
YES
0-23
,
Day
YES
1-31
,
Month
YES
1-12
,
Day
YES
1-7
,
Year
NO
empty,
,
例子:
*
0
特殊字符
*
?
-
,
/
L
day-of-week字段,
和数字联合使用,它的意思就是
means
者范围是很重要的,不然的话,我们会得到一些意想不到的结果。
W
作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个
月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个
月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月
第16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。
注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅
能在day-of-month指明一天,不能是一个范围或列表。
也可以用“LW”来指定这个月的最后一个工作日。
#
day-of-week字段用"6#3"指这个月第3个周五(6指周五,3指第3个)。如果指
定的日期不存在,触发器就不会触发。
C
段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week
字段用“1C”指在这周日或之后包括calendar的第一天。
在MONTH和Day
一些例子
表达式
意思(触发时刻)
0
每天中午12点
0
在2005年的每天10:25
0
在3月里每个周三的14:10和14:44
0
从2002年到2005年里,每个月的最后一个星期五的10:15
0
从当月的第一天开始,然后在每个月每隔5天的12:00
0
每个月第3个周五的10:15
注意在day-of-week和day-of-month字段里使用“?”和“*”的效果。
注意
对“C”的支持并不很完全。
对在day-of-week字段
前你必须在这两个字段中的一个用“?”指定)。
当设置在午夜和凌晨1点之间触发时要仔细。
不触发指令:
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
MISFIRE_INSTRUCTION_DO_NOTHING
7.TriggerListeners
与Trigger相关的事件有:触发器触发,触发器的不触发(参考先前章节),触发
器完成。
public
public
}
与job相关的事件有:job准备执行,job执行完毕。
public
jobException);
}
使用Listeners
创建一个监听器,就是创建一个实现了org.quartz.TriggerListener
org.quartz.JobListener接口的对象。在运行的期间用调度器注册监听器,必须要
给它提供一个名字。监听器能够注册成为全局的或者不是全局的,全局监听器接
受所有的事件,而非全局的则仅接受指定给triggers/jobs了的事件。
监听器是在运行期间被调度器注册的,他们没有伴随jobs和triggers储存在JobStore里。Jobs
和triggers仅储存和它们相关的监听器的名字。因此,每次程序运行时,监听器需要被调度
器再次注册。
scheduler.addGlobalJobListener(myJobListener);
scheduler.addJobListener(myJobListener);
监听器在Quartz并不是经常使用的。
8.SchedulerListeners
和调度器相关的事件有:job/trigger的加入和移出,一些调度器里的错误,调度
器关闭等等。
public
}
创建和注册SchedulerListeners和其他监听器一样,全局和非全局的没有区别。
9.JobStores
JobStore负责保存所有配置到调度器里的工作数据:jobs,triggers,calendars等等。在用
SchedulerFactory得到一个调度器的实例时,我们可以给SchedulerFactory提供一个属性文件
或者一个属性对象来声明使用哪个JobStore。
注意,不要在代码里使用JobStore的实例,这些Quartz都做好了。我们要做的就仅仅告诉
Quartz(通过配置)用哪个JobStore,然后就调用Scheduler接口函数了。
RAMJobStore
利用内存来持久化调度程序信息。这种作业存储类型最容易配置、构造和运行,
但是当应用程序停止运行时,所有调度信息将被丢失。
在属性文件里指定:
org.quartz.jobStore.class
JDBCJobStore
支持的数据库有:Oracle,
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
下一步,我们需要选择一个驱动代理。StdJDBCDelegate是一个用
“vanilla”JDBC代码实现的代理。如果没有其他为你数据库指定的代理,就使
用这个。Quartz开发者们解决的问题都是根据这个代理的来实现的。其他的代理
在org.quartz.impl.jdbcjobstore包或者子包里。包括DB2v6Delegate(DB2
6
(microsoft
WeblogicDelegate(Weblogic的JDBC驱动器使用),OracleDelegate(Oracle
9i使用)。
org.quartz.jobStore.driverDelegateClass
在下一步,我们要配置表的前缀:
org.quartz.jobStore.tablePrefix
最后,我们需要设置用哪个数据源,数据源的名称必须在Quartz属性里定义好。
例如,我们可以给Quartz指定使用“myDS”(在配置属性里的其他地方定义好
了)作为数据源的名字。
org.quartz.jobStore.dataSource
如果调度器很繁忙(例如,执行job的个数和线程池的大小一样),那么我们应
该设置数据源的连接个数在线程池大小+1之上。
org.quartz.jobStore.useProperties这个属性能够设置为“true”(默认为false),
用来指示JDBCJobStore:在JobDataMaps里的所有值都应该是String,这样在能
作为name-value方式储存,而不是在BLOB列里以序列化的格式储存复杂的对
象。从长远看,这样做会很安全,因为你可以避免将非String的类序列化到BLOB
里的类版本问题。