Quartz基础

来源:互联网 发布:360软件商城下载 编辑:程序博客网 时间:2024/05/20 16:14

Quartz是一个完全由java编写的开源作业调度框架。适用于周期性Work需要

1. 启动Quartz

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(); // fire every hourtrigger.setStartTime(TriggerUtils.getEvenHourDate(new Date())); // start on the next even hourtrigger.setName("myTrigger");sched.scheduleJob(jobDetail, trigger);

一旦一个scheduler被实例化,它就可以被启动(start),并且处于驻留模式,直到被关闭(shutdown)。注意,一旦scheduler被关闭(shutdown),则它不能再重新启动,除非重新实例化它。


2. Jobs And Triggers

Job接口是调度任务的父类,所有需要执行的代码都在Job的实现中。

package org.quartz;public interface Job {    public void execute(JobExecutionContext context)      throws JobExecutionException;}


当Job触发器触发时(在某个时刻),Execute (..)就被scheduler所调用。JobExecutionContext对象被传递给这个方法,它为Job实例提供了它的“运行时”环境-一个指向执行这个IJob实例的Scheduler句柄,一个指向触发该次执行的触发器的句柄,IJob的JobDetail对象以及一些其他的条目。


JobDetail对象由Quartz客户端在Job被加入到scheduler时创建。它包含了Job的各种设置属性以及一个JobDataMap对象,这个对象被用来存储给定Job类实例的状态信息。


Trigger对象被用来触发jobs的执行。你希望将任务纳入到进度,要实例化一个Trigger并且“调整”它的属性以满足你想要的进度安排。Triggers也有一个JobDataMap与之关联,这非常有利于向触发器所触发的Job传递参数。

Quartz打包了很多不同类型的Trigger,但最常用的Trigge类是SimpleTrigger和CronTrigger。SimpleTrigger用来触发只需执行一次或者在给定时间触发并且重复N次且每次执行延迟一定时间的任务。CronTrigger按照日历触发,例如“每个周五”,每个月10日中午或者10:15分。 


为什么要分为Jobs和Triggers?很多任务日程管理器没有将Jobs和Triggers进行区分。一些产品中只是将“job”简单地定义为一个带有一些小任务标识的执行时间。其他产品则更像Quartz中job和trigger的联合。而开发Quartz的时候,我们决定对日程和按照日程执行的工作进行分离。(从我们的观点来看)这有很多好处。 例如:jobs可以被创建并且存储在job scheduler中,而不依赖于trigger,而且,很多triggers可以关联一个job.另外的好处就是这种“松耦合”能使与日程中的Job相关的trigger过期后重新配置这些Job,这样以后就能够重新将这些Job纳入日程而不必重新定义它们。这样就可以更改或者替换trigger而不必重新定义与之相连的job标识符。


当向Quartz scheduler中注册Jobs 和Triggers时,它们要给出标识它们的名字。Jobs 和Triggers也可以被放“组”中。“组”对于后续维护过程中,分类管理Jobs和Triggers非常有用。Jobs和Triggers的名字在组中必须唯一,换句话说,Jobs和Triggers真实名字是它的名字+组。如果使Job或者Trigger的组为‘null’,这等价于将其放入缺省的Scheduler.DEFAULT_GROUP组中。


3. 关于Jobs和JobDetails

在所实现的类成为真正的“Job”时,期望任务所具有的各种属性需要通知给Quartz,通过JobDetail类可以完成这个工作.

 

JobDetail jobDetail = new JobDetail("myJob",         // job name                                      sched.DEFAULT_GROUP,   // job group (you can also specify 'null' to use the default group)                                      DumbJob.class);        // the java class to executeTrigger trigger = TriggerUtils.makeDailyTrigger(8, 30);trigger.setStartTime(new Date());trigger.setName("myTrigger");sched.scheduleJob(jobDetail, trigger);public class DumbJob implements Job {    public DumbJob() {    }    public void execute(JobExecutionContext context)      throws JobExecutionException    {      System.err.println("DumbJob is executing.");    }}

 

注意我们传递给scheduler一个JobDetail实例,JobDetail关联一个job,提供job的class,每次scheduler执行job时,在执行execute(...) 这前会创建一个实例.job必须有一个无参构造方法.


你可能想问如何提供配置 job实例.或者保存job状态在执行过程中.答案是JobDataMap.它是JobDetail的一部分.

JobDataMap 

JobDataMap被用来保存一系列的(序列化的)对象,这些对象在Job执行时可以得到。

JobDataMap是Map接口的一个实现,而且还增加了一些存储和读取主类型数据的便捷方法。

jobDetail.getJobDataMap().put("jobSays", "Hello World!");

jobDetail.getJobDataMap().put("myFloatValue", 3.141f);

jobDetail.getJobDataMap().put("myStateData", new ArrayList());


下面的代码展示了在Job执行过程中从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也可以有JobDataMaps与之相关联。当scheduler中的Job被多个有规律或者重复触发的Triggers所使用时非常有用。对于每次独立的触发,你可为Job提供不同的输入数据。 从Job执行时的JobExecutionContext中取得JobDataMap是惯用手段,它融合了从JobDetail和从Trigger中获的JobDataMap,当有相同名字的键时,它用后者的值覆盖前者值。


StatefulJob——有状态任务 

现在,一些关于Job状态数据的附加论题:一个Job实例可以被定义为“有状态的”或者“无状态的”。“无状态的”任务只拥有它们被加入到scheduler时所存储的JobDataMap。这意味着,在执行任务过程中任何对Job Data Map所作的更改都将丢失而且任务下次执行时也无法看到。你可能会猜想出,有状态的任务恰好相反,它在任务的每次执行之后重新存储JobDataMap。有状态任务的一个副作用就是它不能并发执行。换句话说,如果任务有状态,那么当触发器在这个任务已经在执行的时候试图触发它,这个触发器就会被阻塞(等待),直到前面的执行完成。想使任务有状态,它就要实现StatefulJob 接口而不是实现Job接口.


jobs的其它属性 

这里简短地总结一下通过JobDetail对象可以定义Job的其它属性。 

Durability(持久性)-如果一个Job是不持久的, 一旦没有触发器与之关联,它就会被从scheduler 中自动删除。 

Volatility(无常性)-如果一个Job是无常的,在重新启动Quartz i scheduler 时它不能被保持。 

RequestsRecovery(请求恢复能力) -如果一个Job具备“请求恢复”能力,当它在执行时遇到scheduler “硬性的关闭”

       (例如:执行的过程崩溃,或者计算机被关机),那么当scheduler重新启动时,这个任务会被重新执行。

        这种情况下,JobExecutionContext.isRecovering() 属性将是true。 

JobListeners(任务监听器) -一个Job如果有0个或者多个JobListeners监听器与之相关联,当这个Job执行时,监听器被会被通知。


4. 关于Triggers更多内容


Priority

有时,当有多个Triggers时,Quartz没有足够的资源来同时立即处理scheduled的trigger.所以你可能要控制哪个先执行.在这种情况下,你要设置Trigger的priority,如果N个triggers不会同时触发.但此时只有有限的几个线程可


用.这时会先处理级别高的trigger.如果你没有设置级别,默认为5,下面为一个例子:

Calendar cal = Calendar.getInstance();

cal.add(Calendar.MINUTE, 5);Trigger trig1 = new SimpleTrigger("T1", "MyGroup", cal.getTime());Trigger trig2 = new SimpleTrigger("T2", "MyGroup", cal.getTime());Trigger trig3 = new SimpleTrigger("T3", "MyGroup", cal.getTime());JobDetail jobDetail = new JobDetail("MyJob", "MyGroup", NoOpJob.class);// Trigger1 does not have its priority set, so it defaults to 5sched.scheduleJob(jobDetail, trig1);// Trigger2 has its priority set to 10trig2.setJobName(jobDetail.getName());trig2.setPriority(10);sched.scheduleJob(trig2);// Trigger2 has its priority set to 1trig3.setJobName(jobDetail.getName());trig2.setPriority(1);sched.scheduleJob(trig3);// Five minutes from now, when the scheduler invokes these three triggers// they will be allocated worker threads in decreasing order of their// priority: Trigger2(10), Trigger1(5), Trigger3(1)

 

Misfire Instructions——未触发指令 

Trigger的另一个重要属性就是它的“misfire instruction(未触发指令)”。如果因为scheduler被关闭而导致持久的触发器“错过”了触发时间,这时,未触发就发生了。不同类型的触发器有不同的未触发指令。缺省情况下,他们会使用一个“智能策略”指令——根据触发器类型和配置的不同产生不同动作。当scheduler开始时,它查找所有未触发的持久triggers,然后按照每个触发器所配置的未触发指令来更新它们。

开始工程中使用Quartz的时,应熟悉定义在各个类型触发器上的未触发指令。关于未触发指令信息的详细说明将在每种特定的类型触发器的指南课程中给出。可以通过MisfireInstruction属性来为给定的触发器实例配置未触发指令。


TriggerUtils - Triggers Made Easy(TriggerUtils——使Triggers变得容易) 

TriggerUtils类包含了创建触发器以及日期的便捷方法。使用这个类可以轻松地使触发器在每分钟,小时,日,星期,月等触发。使用这个类也可以产生距离触发最近的妙、分或者小时,这对设定触发开始时间非常有用。


TriggerListeners 实现TriggerListener接口的对象将可以收到触发器被触发的通知。


5. SimpleTrigger


SimpleTrigger让任务只在某个时刻执行一次,或者,在某个时刻开始,然后按照某个时间间隔重复执行,在某个时刻结束。SimpleTrigger包括这些属性:开始时间,结束时间,重复次数,重复间隔。所有这属性都是你期望它所应具备的,只有end-time属性有一些条目与之关联。


SimpleTrigger有几个不同的构造函数,下面我们来看看这结果构造函数:

 

public SimpleTrigger(String name, String group,Date startTime,Date endTime,int repeatCount,long repeatInterval)SimpleTrigger Example 1 - Create a trigger that fires exactly once, ten seconds from nowlong startTime = System.currentTimeMillis() + 10000L;SimpleTrigger trigger = new SimpleTrigger("myTrigger", null,new Date(startTime),null,0,0L);SimpleTrigger Example 2 - Create a trigger that fires immediately, then repeats every 60 seconds, foreverSimpleTrigger trigger = new SimpleTrigger("myTrigger", null, new Date(),null,SimpleTrigger.REPEAT_INDEFINITELY,60L * 1000L);SimpleTrigger Example 3 - Create a trigger that fires immediately, then repeats every 10 seconds until 40 seconds from nowlong endTime = System.currentTimeMillis() + 40000L;SimpleTrigger trigger = new SimpleTrigger("myTrigger","myGroup", new Date(),new Date(endTime), SimpleTrigger.REPEAT_INDEFINITELY,10L * 1000L);SimpleTrigger Example 4 - Create a trigger that fires on March 17 of the year 2002 at precisely 10:30 am, and repeats 5 times (for a total of 6 firings) - with a 30 second delay between each firingjava.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);

 

6. 一个可行的Quartz。
在ContextListener的init中,加载所有的Job的配置,并根据这些配置调用相应的Job。同时可以采用StatefulJob保存Job的状态{或者存储到数据库中}。
建立一个action与页面,在页面中可以查看当前所有Job的状态,并采用不同的方式去restart或者destory一个Job。

 

原创粉丝点击