Quartz学习笔记(一)
Quartz特点
1)Quartz能嵌入到任何独立的应用中运行。?
2)Quartz能在应用服务器或者?Servlet?容器中实例化,并且能够参与?XA?事务。?
3)Quartz能够以独立的方式运行(在它自己的Java虚拟机中),可以通过?RMI使用
Quartz。?
4)Quartz可以被实例化为独立程序的集群(有负载均衡和容错能力)。?
Quartz功能介绍
任务执行(Job?Execution)
1)?任务是任何实现简单?Job?接口的?Java?类,这样开发者能够执行任何完成他们工作
的任务。
2)?任务类的实例可以由?Quartz实例化,也可以由你的程序框架实例化。
当触发器被触发时,日程管理器将会通知某个或者多个实现了JobListener?或?
TriggerListener的对象(监听器可以是简单的Java对象,或者?EJBs,或者?JMS?消息发布器,等等)。这些监听器在任务执行完毕后也会接到通知。
3)?任务被完成后,他们会返回一个“任务完成码(JobCompletionCode)”,这个
“任务完成码”告知日程管理器任务执行的结果是成功还是失败。日程管理器会根据成功或者失败码来采取措施,比如:立即重新执行任务
任务持久化(Job?Persistence)
1)?Quartz设计中包括了一个JobStore接口,这样,实现这个接口的?Job多种机制实现Job?的存储。
2)?存储在数据库中:通过使用?JDBCJobStore,所有的?Jobs和?Triggers?被配置为“non-volatile”(不
轻快)的方式。即,通过?JDBC?存储在关系数据库中。
3)?存储在RAM中:通过使用?RAMJobStore,所有Jobs和?Triggers?被存储在?RAM。因此,在程序执行中没有被持久化,但这种方式的优点就是不需要外部数据库。
事务(Transactions)
1)?Quartz通过JobStoreCMT(JDBCJobStore的一个子类)可参与?JTA?事务。
2)?Quartz可以管理JTA?(工作任务分析)事务(开始或者提交事务)。
集群(Clustering)
1)?Fail-over.(容错)
2)?Load?balancing.(负载均衡)
监听器及插件(Listeners?&?Plug-Ins)
1)?应用可以通过实现一个或者多个监听器接口来实现捕捉日程事件,以监视或控制任务/触发器的行为。
2)?可以通过插件的机制来扩展?Quartz?的功能。例如:记录任务执行历史的日志,或者从文件中载入任务和触发器的定义。
3)?Quartz自带了一些“factory?built(内建)”的插件和监听器。
什么是Quartz
Quartz是一个任务日程管理系统,这个系统可以与任何其他软件系统集成或者一起
用。“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。
Quartz相当“轻量”,并且需要非常少的步骤/配置,如果需求比较基本,Quartz确实非常容易使用。
Quartz具有容错性,并且可以在你系统重起的时候持久化(记住)被纳入日程的任务。
Quartz用一个小Java库发布文件(.jar文件),这个库文件包含了所有?Quartz核心功能。这些功能的主要接口(API)是Scheduler接口。它提供了简单的操作,例如:将任务纳入日程或者从日程中取消,开始/停止/暂停日程进度。
如果你想将软件组件的执行纳入到日程中,它们只需简单地实现?Job?接口,这个接口有一个?execute()方法。如果希望在日程安排的时间到达时通知组件,那么这些组件应实现?TriggerListener或者?JobListener接口。
Quartz主过程可以在应用中启动或者运行,也可以作为一个独立的应用(带有RMI<远程服务接口>接口),或者在一个J2EE?应用服务器中运行,并且可作为其它?J2EE组件的一种引用资源。
Quartz与java.util.Timer(JDK1.3起)的区别
1.Java?定时器没有持久化机制。??
2.Java?定时器的日程管理不够灵活(只能设置开始时间、重复的间隔,设置特定的日期、时间等)??
3.Java?定时器没有使用线程池(每个Java?定时器使用一个线程)??
4.Java?定时器没有切实的管理方案,你不得不自己完成存储、组织、恢复任务的措施。
夏令时和触发器
SimpleTrigger?总是每隔若干毫秒触发,而同夏令时没有关系。
CronTrigger?总是在给定的时间触发,然后计算它下次触发的时间。
开始使用Quartz
Job:接口:只有一个方法:oid?execute(JobExecutionContext?context)。
JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描?述、关联监听器等信息,JobDetail承担了这一角色。
通过该类的构造函数可以更具体地了解它的功用:JobDetail(java.lang.String?name,?java.lang.String?group,?java.lang.Class?jobClass),该构造函数要求指定Job的实现类,以及任务在Scheduler中的组名和Job名称;
Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触?发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规?则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等。
Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简?单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时?间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或?包含某些时间点。
Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在?Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯?一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,?允许外部通过组及名称访问和控制容器中Trigger和JobDetail。
Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应?多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。?Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和?Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下?文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler#?getContext()获取对应的SchedulerContext实例。
ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。
Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采用?不同的执行方案。无状态任务在执行时拥有自己的JobDataMap拷贝,对JobDataMap的更改不会影响下次的执行。而有状态任务共享共享同一个?JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,也即每次执行任务后都会对后面的执行?发生影响。
如果Quartz使用了数据库持久化任务调度信息,无状态的JobDataMap仅会在Scheduler注册任务时保持一次,而有状态任务对应的JobDataMap在每次执行任务后都会进行保存。
Trigger自身也可以拥有一个JobDataMap,其关联的Job可以通过?JobExecutionContext#getTrigger().getJobDataMap()获取Trigger中的JobDataMap。不管?是有状态还是无状态的任务,在任务执行期间对Trigger的JobDataMap所做的更改都不会进行持久,也即不会对下次的执行产生影响。
监听体系:Quartz拥有完善的事件和监听体系,大部分组件都拥有事件,如任务执行前事件、任务执行后事件、触发器触发前事件、触发后事件、调度器开始事件、关闭事件等等,可以注册相应的监听器处理感兴趣的事件。
SimpleTrigger:
SimpleTrigger拥有多个重载的构造函数,用以在不同场合下构造出对应的实例:
1)SimpleTrigger(String?name,?String?group):通过该构造函数指定Trigger所属组和名称;
2)SimpleTrigger(String?name,?String?group,?Date?startTime):除指定Trigger所属组和名称外,还可以指定触发的开发时间。
3)SimpleTrigger(String?name,?String?group,?Date?startTime,?Date?endTime,?int?repeatCount,?long?repeatInterval):除指定以上信息外,还可以指定结束时间、重复执行次数、时间间隔等参数;
4)SimpleTrigger(String?name,?String?group,?String?jobName,?String?jobGroup,?Date?startTime,?Date?endTime,?int?repeatCount,?long?repeatInterval):这是最复杂的一个构造函数,在指定触发参数的同时,还通过jobGroup和jobName,让该Trigger和?Scheduler中的某个任务关联起来。
CronTrigger:
Quartz使用类似于Linux下的Cron表达式定义时间规则,Cron表达式由6或7个由空格分隔的时间字段组成,如表1所示:
分别代表秒、分钟、小时、日期、月份、星期、年
位置
时间域名
允许值
允许的特殊字符
1
秒
0-59
,?-?*?/
2
分钟
0-59
,?-?*?/
3
小时
0-23
,?-?*?/
4
日期
1-31
,?-?*???/?L?W?C?
5
月份
1-12
,?-?*?/
6
星期
1-7
,?-?*???/?L?C?#
7
年(可选)
空值1970-2099
,?-?*?/
Cron表达式的时间字段除允许设置数值外,还可使用一些特殊的字符,提供列表、范围、通配符等功能,细说如下:
1)星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,*在分钟字段时,表示“每分钟”;
2)问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;
3)减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
4)逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;
5)斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;
6)L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的?31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后?X天”,例如,6L表示该月的最后一个星期五;
7)W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星?期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;
8)LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;
9)井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;
??10)?C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于Quartz使用类似于Linux下的Cron表达式定义时间规则,Cron表达式由6或7个由空格分隔的时间字段组成