2. 调度 Quartz ScanDirectoryJob
到目前为止,我们已经创建了一个 Quartz job,但还没有决定怎么处置它--明显地,我们需以某种方式为这个 Job 设置一个运行时间表。时间表可以是一次性的事件,或者我们可能会安装它在除周日之外的每个午夜执行。你即刻将会看到,Quartz Schduler 是框架的心脏与灵魂。所有的 Job 都通过 Schduler 注册;必要时,Scheduler 也会创建 Job 类的实例,并执行实例的 execute() 方法。
Scheduler 会为每一次执行创建新的 Job 实例Scheduler 在每次执行时都会为 Job 创建新的实例。这就意味着 Job 的任何实例变量在执行结束之后便会丢失。与此相反概念则可用述语有状态的(J2EE世界里常见语)来表达,但是应用 Quartz ,一个有状态的 Job 并不用多少开销,而且很容易的配置。当你创建一个有状态的 Job 时,有一些东西对于 Quartz 来说是独特的。最主要的就是不会出现两个有着相同状态的 Job 实例并发执行。这可能会影响到程序的伸缩性。这些或更多的问题将在以后的章节中详细讨论。 |
·创建并运行 Quartz Scheduler
在具体谈论 ScanDirectoryJob 之前,让我们大略讨论一下如何实例化并运行 Quartz Scheduler 实例。代码 3.3 描述了创建和启动一个 Quartz Scheduler 实例的必要且基本的步骤。
代码 3.3 运行一个简单的 Quartz 调度器
|
package
org.cavaness.quartzbook.chapter3;
package
org.cavaness.quartzbook.chapter3;
import
java.util.Date;
import
org.apache.commons.logging.Log;
import
org.apache.commons.logging.LogFactory;
import
org.quartz.Scheduler;
import
org.quartz.SchedulerException;
import
org.quartz.impl.StdSchedulerFactory;
public
class
SimpleScheduler {
static
Log logger = LogFactory.getLog(SimpleScheduler.
class
);
public
static
void
main(String[] args) {
SimpleScheduler simple =
new
SimpleScheduler();
simple.startScheduler();
}
public
void
startScheduler() {
Scheduler scheduler =
null
;
try
{
// Get a Scheduler instance from the Factory
scheduler = StdSchedulerFactory.getDefaultScheduler();
// Start the scheduler
scheduler.start();
logger.info(
"Scheduler started at "
+
new
Date());
}
catch
(SchedulerException ex) {
// deal with any exceptions
logger.error(ex);
}
}
}
|
运行上面 3.3 的代码,会有日志输出,你会看到类似如下的输出:
INFO [main] (SimpleScheduler.java:30) - Scheduler started at Mon Sep 05 13:06:38 EDT 2005
关闭 Quartz Info 级别的日志信息 假如你搭配着 Log4J 使用 Commons Logging 日志框架,就像本书的例子那样,你也许需要把除本书例子外,其他的所有 Info 级别以上的日志信息关闭掉。这是因为 Quartz 中 Debug 和 Info 级别的日志信息数量上大体相当。当你明白了 Quartz 在做什么的时候,你真正关注的信息却淹没在大量的日志信息中。为了不至于这样,你可以创建一个文件 log4j.properties 指定只输出 ERROR 级别信息,但是要为本书中的例子设置定显示 INFO 级别的信息。这里有一个 log4j.properties 的例子文件来达到这个目的:
文件 log4j.properties 配置了默认向标准输出只输出 ERROR 级别以上的日志信息,但是任何在包 org.cavaness.quartzbook 中的 INFO 以上级别的信息也会输出。这有赖于以上属性文件最后一行配置。 |
代码 3.3 展示了启动一个 Quartz 调度器是那么的简单。当调度器起来之后,你可以利用它做很多事情或者获取到它的许多信息。例如,你也许需要安排一些 Job 或者改变又安排在调度器上 Job 的执行次数。你也许需要让调度器处于暂停模式,接着再次启动它以便重新执行在其上安排的作业。当调度器处于暂停模式时,不执行任何作业,即使是作业到了它所期待的执行时间。代码 3.4 展示了怎么把调度器置为暂停模式然后又继续运行,这样调度器会从中止处继续执行。
代码 3.4 设置调度器为暂停模式
|
private
void
modifyScheduler(Scheduler scheduler) {
try
{
if
(!scheduler.isInStandbyMode()) {
// pause the scheduler
scheduler.standby();
}
// Do something interesting here
// and then restart it
scheduler.start();
}
catch
(SchedulerException ex) {
logger.error(ex);
}
}
|
代码 3.4 中的片断仅仅是一个最简单的例子,说明了当你执有一个 Quartz 调度器的引用,你可以利用它做一些你有感兴趣的事情。当然了,并非说 Scheduler 只有处于暂停模式才能很好的利用它。例如,你能在调度器处于运行状态时,安排新的作业或者是卸下已存在的作业。我们将通过本书的一个调度器尽可能的去掌握关于 Quartz 更多的知识。
上面的例子看起来都很简单,但千万不要被误导了。我们还没有指定任何作业以及那些作业的执行时间表。虽然代码 3.3 中的代码确实能启动运行,可是我们没有指定任何作业来执行。这就是我们下一节要讨论的。
·编程式安排一个 Quartz Job
所有的要 Quartz 来执行的作业必须通过调度器来注册。大多情况下,这会在调度器启动前做好。正如本章前面说过,这一操作也提供了声明式与编程式两种实现途径的选择。首先,我们讲解如何用编程的方式;接下来在本章,我们会用声明的方式重做这个练习。
因为每一个 Job 都必须用 Scheduler 来注册,所以先定义一个 JobDetail,并关联到这个 Scheduler 实例。见代码 3.5。
代码 3.5. 编程式安排一个 Job