本篇讲述:Job、JobDetail、JobDataMap、JobExecutionContext的用法。
1、Job
Quartz中Job必须实现Job接口。实现了Job接口的Job类描述了被执行的任务。Job接口如下:
package org.quartz;
public interface Job {
void execute(JobExecutionContext context)throws JobExecutionException;
}
Job被触发时,execute方法会被调用。在execute方法被执行时,仅允许抛出一个JobExecutionException类型异常。因此需要将整个要执行的内容包括在一个'try-catch'块中。Job能够使用它向scheduler提供各种指示。
2、JobExecutionContext
JobExecutionContext描述了Job执行的上下文环境,包括执行这个Job的Scheduler对象句柄、Job的Trigger对象句柄、JobDataMap对象。
3、JobDetail
在我们将Job加入Scheduler时,会用到JobDetail对象。该对象包含了Job的各种设置属性以及一个JobDataMap对象。
JobDetail jobDetail = new JobDetail("myJob","myGroup",MyJob.class)
说明:
myJob:job 名
myGroup:job 组(为'null'时,使用缺省的组sched.DEFAULT_GROUP)
MyJob.class:要被执行的Java类。
这里只指定了Job的类,每次scheduler执行这个任务时,它就创建这个类的新实例,然后调用该实例的execute(..)方法。对这种行为的一个推论就是Job类必须有一个无参数的构造函数。另外一个推论就是它使得Job类中定义的成员数据失去意义,因为这些成员数据值在每次执行的时候被“清空”了。
通过JobDetail对象可以定义Job的其它属性。
• Durability(持久性)-如果一个Job是不持久的, 一旦没有触发器与之关联,它就会被从scheduler 中自动删除。
• Volatility(无常性)-如果一个Job是无常的,在重新启动Quartz i scheduler 时它不能被保持。
• RequestsRecovery(请求恢复能力) -如果一个Job具备“请求恢复”能力,当它在执行时遇到scheduler “硬性的关闭”(例如:执行的过程崩溃,或者计算机被关机),那么当scheduler重新启动时,这个任务会被重新执行。这种情况下,JobExecutionContext.isRecovering() 方法的返回值将是true。
• JobListeners(任务监听器) -一个Job如果有0个或者多个JobListeners监听器与之相关联,当这个Job执行时,监听器被会被通知。更多有关JobListeners的讨论见TriggerListeners & JobListeners章节。
4.JobDataMap
JobDataMap被用来保存一系列的(序列化的)对象,这些对象在Job执行时可以得到。JobDataMap是Java Map接口的一个实现,而且还增加了一些存储和读取主类型数据的便捷方法。
如果使用一个持久的JobStore,那么必须注意存放在JobDataMap中的内容。因为放入JobDataMap中的内容将被序列化,而且容易出现类型转换问题。很明显,标准Java类型将是非常安全的,但除此之外的类型,任何时候,只要有人改变了你要序列化其实例的类的定义,就要注意是否打破了程序的兼容性。另外,你可以对JobStore和JobDataMap采用一种使用模式:就是只把主类型和String类型存放在Map中,这样就可以减少后面序列化的问题。
Triggers也可以有JobDataMaps与之相关联。当scheduler中的Job被多个有规律或者重复触发的Triggers所使用时非常有用。对于每次独立的触发,你可为Job提供不同的输入数据。
从Job执行时的JobExecutionContext中取得JobDataMap是惯用手段,它融合了从JobDetail和从Trigger中获的JobDataMap,当有相同名字的键时,它用后者的值覆盖前者值。
5.StatefulJob
有状态和无状态任务
一个Job实例可以被定义为“有状态的”或者“无状态的”。“无状态的”任务只拥有它们被加入到scheduler时所存储的JobDataMap。这意味着,在执行任务过程中任何对Job Data Map所作的更改都将丢失而且任务下次执行时也无法看到。你可能会猜想出,有状态的任务恰好相反,它在任务的每次执行之后重新存储JobDataMap。有状态任务的一个副作用就是它不能并发执行。换句话说,如果任务有状态,那么当触发器在这个任务已经在执行的时候试图触发它,这个触发器就会被阻塞(等待),直到前面的执行完成。
想使任务有状态,它就要实现StatefulJob接口而不是实现Job接口。
6.其他
可以创建一个单独的Job类,并且通过创建多个JobDetails实例来将它的多个实例存储在scheduler中,这样每个JobDetails对象都有它自己的一套属性和JobDataMap,而且将它们都加入到scheduler中。
当触发器被触发的时候,通过Scheduler中配置的JobFactory来实例化与之关联的Job类。缺省的JobFactory只是简单地对Job类调用newInstance()方法。创建己JobFactory可以利用应用中诸如Ioc或者DI容器所产生或者初始化的Job实例。