Quartz 的使用

Quartz 的使用
Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。Quartz 允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz 的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。虽然可以通过属性文件(在属性文件中可以指定 JDBC 事务的数据源、全局作业和/或触发器侦听器、插件、线程池,以及更多)配置 Quartz,但它根本没有与应用程序服务器的上下文或引用集成在一起。结果就是作业不能访问 Web 服务器的内部函数。

本文内容
宋体Using Quartz
Jobs And Triggers
More About Triggers
More About Jobs & JobDetails
SimpleTrigger
CronTrigger
TriggerListeners and JobListeners
SchedulerListeners
JobStores
Configuration, Resource Usage and SchedulerFactory
关于Quartz中的几个表

Using Quartz
宋体Scheduler的实例化,我们需要使用SchedulerFactory.他也可以通过JNDI实例化
Scheduler被实例化他就可以启动,放置一些行为,关闭。注意:一个Scheduler被关闭,他不能通过新的实例重新启动。Triggers 不能被触发(execute方法),直到它已经启动才可以,在Scheduler停止时,也不能出发

代码片段
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
sched.start();
JobDetail jobDetail = new JobDetail("myJob", null, DumbJob.class);
Trigger trigger = TriggerUtils.makeHourlyTrigger(); // 每小时触发一次 trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));
//设置开始时间为下一个小时
trigger.setName("myTrigger");
sched.scheduleJob(jobDetail, trigger);

//可以看下TriggerUtils类 设定时间的

Jobs And Triggers
Scheduler作业类,必须实现org.quartz.Job接口,实现execute方法
如:
package org.quartz;
public interface Job {
public void execute(JobExecutionContext context)
throws JobExecutionException; }
不难猜到当job的trigger触发时,execute()方法将被Scheduler调用
JobExecutionContext 对象被传递到方法中,提供关于“run-time” 环境的信息。
JobDetail 对象被Quartz client创建,添加Job到这个scheduler中,他包含不用的属性设置,为了Job、JobDataMap (可以保存一些信息给你job class的实例。)
Trigger 对象触发job的execute,它同样可以有JobDataMap ,它可以有不同的类型,但一般用SimpleTrigger and CronTrigger.
SimpleTrigger如果你需要‘one-shot’ 执行(在某个时间执行一个任务,或者在某个时候开始执行,并在一段时间内执行n次,)
CronTrigger 按一个calendar-like 执行,如每年的……时候执行。
Scheduler好处是将,时间表和任务分开了。如,工作可以被创建和存储,而不依赖一个触发,许多触发可以联合多个工作。另一个是loose-coupling (松耦合)
Jobs and triggers 可以被放在‘groups’ 中,便于管理,job的名字和triggers 在一个组必须是唯一的。Identifiers :name+group. Job or Triggerd的组为 ‘null’,相当与指定Scheduler.DEFAULT_GROUP.

More About Triggers
Calendar Interface
package org.quartz;
public interface Calendar {
public boolean isTimeIncluded(long timeStamp);
public long getNextIncludedTime(long timeStamp); }

Using Calendars
HolidayCalendar cal = new HolidayCalendar();
cal.addExcludedDate( someDate );
sched.addCalendar("myHolidays", cal, false);
Trigger trigger = TriggerUtils.makeHourlyTrigger(); // fire every one hour interval
trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date())); // start on the next even hour
trigger.setName("myTrigger1");
trigger.setCalendarName("myHolidays");
// .. schedule job with trigger
Trigger trigger2 = TriggerUtils.makeDailyTrigger(8, 0); // fire every day at 08:00
trigger.setStartTime(new Date()); // begin immediately
trigger2.setName("myTrigger2");
trigger2.setCalendarName("myHolidays");
// .. schedule job with trigger2
More About Jobs & JobDetails
public class DumbJob implements Job {
public DumbJob() { }
public void execute(JobExecutionContext context)
throws JobExecutionException
{ System.err.println("DumbJob is executing."); } }
1、must have a no-arguement constructor
2、their values would be 'cleared' every time the job executes

provide properties/configuration for a Job instance 使用 JobDataMap
JobDataMap
Setting Values in a JobDataMap
jobDetail.getJobDataMap().put("jobSays", "Hello World!"); jobDetail.getJobDataMap().put("myFloatValue", 3.141f); jobDetail.getJobDataMap().put("myStateData", new ArrayList());

Getting Values from a JobDataMap
public class DumbJob implements Job {
public DumbJob() { } //必须的
public void execute(JobExecutionContext context)
throws JobExecutionException
{ String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays); } }
Triggers can also have JobDataMaps associated with them
Getting Values from the JobExecutionContext convenience/merged JobDataMap
public class DumbJob implements Job {
public DumbJob() { }
public void execute(JobExecutionContext context)
throws JobExecutionException
{ String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDataMap();
// Note the difference from the previous example
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays); } }
It is a merge of the JobDataMap found on the JobDetail and the one found on the Trigger, with the value in the latter overriding any same-named values in the former.

在两次作业执行之间,不会去维护作业执行时JobDataMap的状态改变。
如果你需要能增、删,改JobDataMap的值,而且能让作业在下次执行时能看到这个状态改变,
则需要用Quartz有状态作业。
有状态作业实现了org.quartz.StatefulJob接口。
SimpleTrigger
SimpleTrigger 实例相当原始。在创建对象之后,设置几个基本属性以立即调度任务。还有其他许多方式可以操纵 SimpleTrigger。除了指定重复次数和重复间隔,还可以指定作业在特定日历时间执行,只需给定执行的最长时间或者优先级(稍后讨论)。执行的最长时间可以覆盖指定的重复次数,从而确保作业的运行不会超过最长时间。

One of SimpleTrigger's Constructors
public SimpleTrigger(String name, String group, Date startTime, Date endTime,
int repeatCount, long repeatInterval)

Misfire Instruction Constants of SimpleTrigger
MISFIRE_INSTRUCTION_FIRE_NOW
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

CronTrigger
CronTrigger 支持比 SimpleTrigger 更具体的调度,而且也不是很复杂。基于 cron 表达式,CronTrigger 支持类似日历的重复间隔,而不是单一的时间间隔
cron 触发器规范:
Seconds Minutes Hours Day-of-month Month Day-of-Week Year
秒 分 时 天 月 周 年
Seconds 0-59 , - * /
Minutes 0-59 , - * /
Hours 0-23 , - * /
Day-of-month 1-31 , - * ? / L C
Month 1-12 or JAN-DEC , - * /
Day-of-Week 1-7 or SUN-SAT , - * ? / L C #
Year (Optional) empty, 1970-2099 , - * /
关于字符串的设置(在cron expression中所有字符不区分大小写):

"*"字符被用来指定所有的值,例如,"*"在分钟字段时表示每一分钟
"?"字符在天和周字段中使用。表示没有指定值,天和周字段指定一个,但不能两个都指定为"?"
'-'字符被用来设置范围,比如"10-12"在小时字段的意义为"10点,11点,12点"
','字符被用来设置添加的值,例如在周字段设置"MON,WED,FRI"的意义即为:在周一、周三、周五激活
'/'字符被用来设置增量。例如秒字段设置"0/15"的意思为从0开始,每15秒触发,即在0、15、30、45秒触发,秒字段设置"5/15"的意思为,从5开始,第15秒触发,即在5、20、35、50秒触发.你还可以在'*'后面使用'/'字符,在这种情况下'*'与字符'0'意义相同。
'L'在天字段和周字段中使用。'L'字符是'last'的缩写,但在两个字段中,它有不同的意义。例如,'L'在天字段的意思为月的最后一天,在一月为31,非闰月2月为28。如果在'L'用在周字段中,意思为'7'(周六),即周末,一周最后一天。但如果在周字段的另一个值后面,他意味着最后一个星期几在指定月。例如'6L'意味着月的最后一个周五.在使用'L'选项时,指定列表或者范围是非常重要的,不然容易被结果搞乱。
'#'被用在周字段。它用来指定第几个周几中激活。如:"6#3"-->月的第三个周五;"2#1"-->月的第一个周一;"4#5"-->月的第五个周三。要注意,如果要使用#后面跟5,但当月并没有第五周相应的周天,那么job将不被执行(激活);
'C'被用在天和周字段中,'C'是'calendar'的缩写.(不太明白,关于日历的支持还不完善)
同时在周、天中使用'?'还不完善,目前只在两者中使用一个。
要注意'?'和'*'在周和天字段带来的影响。
注意以下例子:
1、"0 15 10 * * 6L 2002-2005" 在2002至2005年的每月每天的10:15触发。
2、"0 15 10 ? * 6L 2002-2005" 在2002至2005年的每月的最后一个周五触发。
1中*表示每天,覆盖了6L(最后一个周五)



TriggerListeners and JobListeners
The org.quartz.TriggerListener Interface
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);}

The org.quartz.JobListener Interface
public interface JobListener {
public String getName();
public void jobToBeExecuted(JobExecutionContext context);
public void jobExecutionVetoed(JobExecutionContext context);
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException);}

Using Your Own Listeners
implements either the org.quartz.TriggerListener and/or org.quartz.JobListener interface
"global" or "non-global".
Global listeners receive events for ALL triggers/jobs, and
non-global listeners receive events only for the specific triggers/jobs that explicitely
name the listener in their getTriggerListenerNames() or getJobListenerNames() properties.

Adding a JobListener to the Scheduler
scheduler.addGlobalJobListener(myJobListener);
or
scheduler.addJobListener(myJobListener);


SchedulerListeners
The org.quartz.SchedulerListener Interface
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();}

JobStores
Quartz 提供了两种不同的方式用来把与作业和触发器有关的数据保存在内存或数据库中。第一种方式是 RAMJobStore 类的实例,这是默认设置。这个作业仓库最易使用,而且提供了最佳性能,因为所有数据都保存在内存中。这个方法的主要不足是缺乏数据的持久性。因为数据保存在 RAM 中,所以应用程序或系统崩溃时,所有信息都会丢失。
为了修正这个问题,Quartz 提供了 JDBCJobStore。顾名思义,作业仓库通过 JDBC 把所有数据放在数据库中。数据持久性的代价就是性能降低和复杂性的提高。

JDBCJobStore 需要两步:首先必须创建作业仓库使用的数据库表。
第二,必须定义一些属性
RAMJobStore
Configuring Quartz to use RAMJobStore
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

JDBCJobStore
Configuring Quartz to use JobStoreTx
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
Configuring JDBCJobStore to use a DriverDelegate
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
Configuring JDBCJobStore with the Table Prefix
org.quartz.jobStore.tablePrefix = QRTZ_
Configuring JDBCJobStore with the name of the DataSource to use
org.quartz.jobStore.dataSource = myDS
Configuration, Resource Usage and SchedulerFactory
quartz.properties 文件

The major components that need to be configured before Quartz can do its work are:
ThreadPool
JobStore
DataSources (if necessary)
The Scheduler itself

The properties for configuring various aspect of a scheduler are described in these sub-documents:
Main Configuration (configuration of primary scheduler settings, transactions)
Configuration of ThreadPool (tune resources for job execution)
Configuration of Listeners (your application can recieve notification of scheuled events)
Configuration of Plug-Ins (add functionality to your scheduler)
Configuration of RMI Server and Client (use a Quartz instance from a remote process)
Configuration of RAMJobStore (store jobs and triggers in memory)
Configuration of JDBC-JobStoreTX (store jobs and triggers in a database via JDBC)
Configuration of JDBC-JobStoreCMT (JDBC with JTA containter-managed transactions)
Configuration of DataSources (for use by the JDBC-JobStores)
Configuration of Clustering (achieve fail-over and load-balancing with JDBC-JobStore)
关于Quartz中的几个表
QRTZ_TRIGGERS
存放Trigger(包括SIMPLE_TRIGGERS和CRON_TRIGGERS)和jobDetail的对应关系
QRTZ_TRIGGER_LISTENERS
QRTZ_SIMPLE_TRIGGERS 存储简单触发器
QRTZ_SCHEDULER_STATE
QRTZ_PAUSED_TRIGGER_GRPS
QRTZ_LOCKS
QRTZ_JOB_LISTENERS
QRTZ_JOB_DETAILS 存储jobDetail
QRTZ_FIRED_TRIGGERS
QRTZ_CRON_TRIGGERS 存储复杂触发器CRON_TRIGGERS
QRTZ_CALENDARS
QRTZ_BLOB_TRIGGERS 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值