多數讀者都較容易從一個簡明扼要的例子中明白一個東西。作為寫作者,要注意避免把一章的內容精簡地幾乎什么都沒了;作為讀者呢,需要有耐心并且要進一步相信其后相關的章節應該去閱讀,盡管這個例子看起來是如此之簡單。
有了這種初衷,這一章將為你介紹如何用 Quartz 框架創建一個簡單的應用程序,它展示了一個典型的應用。這個例子將讓你領略到創建和執行一個簡單應用的必要步驟。通過本章的學習,為你學習本書的后續章節打下了堅實的基礎。
1. "Hello, World" Quartz 工程
本示例應用比起眾所周知的 System.out.println("Hello world from Quartz") 來還是要有趣些。當我們用 Quartz 執行一個作業時,總是希望它能為我們執行一些有趣且有意義的任務。因此,接下來我們就要做一些有用且有用的事情。
本章向您演示如何創建這么一個 Quartz 作業,Quartz 應用通知它要做事情的時候,就會去掃描指定的目錄尋找 XML 文件。假如在指定目錄中找到了一個或多個 XML 文件的話,它將會打印出文件的一些概要信息。是不是很有意義且有趣的,你說呢?但愿,你還能進一步延伸:作業在檢測到某一目錄下的特定文件后,還要依據那些文件做其他許多你感興趣的事。你可能會想把它們 FTP 到一臺遠程機器上,或者把它們作為電子郵件的附件發送。也許那是些客戶發過來的訂單文件,我們需要讀取它們后插入到數據庫中。無限可能性;我們會在本書的后面部分討論它們。
我們努力讓這一部分闡述地直截了當并且只涉及本質要義。然而,我們也會研究到一些會影響到 Quartz 應用程序運行行為的常用配置選項。我們假定你很好的掌握了 Java 語言;我們基本不會花時間去解翻譯 Java 語言方面東西。
最后,本章的結束部分會簡單的討論怎么打包這個示例應用。在構建和打包 Java 工程時 Apache Ant 是我們的選擇;Quartz 應用程序也不例外。
·建立 Quartz 工程
首要步驟是要建立起本工程的開發環境。你可以選擇任何自己喜歡的開發工具或者感覺比較好的IDE;Quartz 并不發固執的要求你用哪一個工具。假如你還是接觸Java沒多久的開發者,Eclipse 會讓你感覺特別的舒適;我們在本書的所有例子都是在 Eclipse 中講解。
如果你還沒有 Eclipse 的話,你可以從 http://eclipse.org 下載。你可以選擇下載 3.x 的某個版本。在 http://www.eclipse.org/eclipse/index.html 可查看 Eclipse 的文檔;你會找到能幫助你上手 Eclipse 的所有需要的資料。
·在 Eclipse 中配置使用 Quartz
我們只為本書中的所有例子創建一個 Java 工程;每一章的源代被放在單獨的目錄中。圖 3.1 顯示了Eclipse 中的 Quartz 工程。

你必須引入幾個 JAR 到工程中才能成功構建它們。首先,你需要 Quartz 的二進制版本,包的名字是 quartz-<version>.jar。Quartz 還需要幾個第三方庫;這依賴于你要用到框架的什么功能而定,Commons Digester 庫可以在 <QUARTZ_HOME>/lib/core 和 <QUARTZ_HOME>/lib/optional 目錄中找到。表 3.1 列出了Quartz 依賴包的更多信息。
把 Quartz 源代碼加入到 Eclipse 中來是個很好主意。這可以給你帶來兩方面的益處。其一,它允許你設置斷點并跟入到 Quartz 源代碼中。其二,它還幫助你深入淺出的學習這一框架。如果你要探察 Quartz 是怎么工作的,或者有時候為什么不能正常工作,那么這時候你真正需要手邊有它的一套源代碼。這是商業軟件無法給你的便利。
Quartz Application 和 Job 的區別 我們在這里打斷一下,有必要解釋這個容易搞混的概念。我們用述語“Quartz Application”來指代任何使用到 Quartz 框架的軟件程序。通常一個應用程序中會使用許多庫,只要用上了 Quartz,我們認為這就是我們在本書上所討論的 Quartz Application。另一方面,我們所說的 Quartz Job,是指執行一些作業的特定的 Java 類。正常地,在一個 Quartz Application 中會包括許多不同類型的 Job,每一個作業會對應有一個具體 Java 類。這兩個概念不能交換使用。 |
·創建一個 Quartz Job 類
每一個 Quartz Job 必須有一個實現了 org.quartz.Job 接口的具體類。這個接口僅有一個要你在 Job 中實現的方法,execute(),方法 execute() 的原型如下:
public void execute(JobExecutionContext context) throws JobExecutionException;
當 Quartz 調度器確定到時間要激發一個 Job 的時候,它就會生成一個 Job 實例,并調用這個實例的 execute() 方法。調度器只管調用 execute() 方法,而不關心執行的結果,除了在作業執行中出問題拋出的 org.quartz.JobExecutionException 異常。
你可以在 execute() 方法中執行你的業務邏輯:例如,也許你會調用其他構造的實例上的方法,發送一個電子郵件、FTP 傳一個文件、調用一個 Web 服務、調用一個EJB、執行一個工作流,或者像我們的例子中那樣,檢查某個特定的目錄下是否存在文件。
代碼 3.1 是我們的第一個 Quartz job,它被設計來掃描一個目錄中的文并顯示文件的詳細信息。
代碼 3.1. ScanDirectoryJob 例子
- package org.cavaness.quartzbook.chapter3;
- import java.io.File;
- import java.util.Date;
- import org.apache.commons.logging.Log;
- import Org.apache.commons.logging.LogFactory;
- import org.quartz.Job;
- import org.quartz.JobDataMap;
- import org.quartz.JobDetail;
- import org.quartz.JobExecutionContext;
- import org.quartz.JobExecutionException;
- /**
- * <p>
- * A simple Quartz job that, once configured, will scan a
- * directory and print out details about the files found
- * in the directory.
- * </p>
- * Subdirectories will filtered out by the use of a
- * <code>{@link FileExtensionFileFilter}</code>.
- *
- * @author Chuck Cavaness
- * @see java.io.FileFilter
- */
- public class ScanDirectoryJob implements Job {
- static Log logger = LogFactory.getLog(ScanDirectoryJob.class);
- public void execute(JobExecutionContext context)
- throws JobExecutionException {
- // Every job has its own job detail
- JobDetail jobDetail = context.getJobDetail();
- // The name is defined in the job definition
- String jobName = jobDetail.getName();
- // Log the time the job started
- logger.info(jobName + " fired at " + new Date());
- // The directory to scan is stored in the job map
- JobDataMap dataMap = jobDetail.getJobDataMap();
- String dirName = dataMap.getString("SCAN_DIR");
- // Validate the required input
- if (dirName == null) {
- throw new JobExecutionException( "Directory not configured" );
- }
- // Make sure the directory exists
- File dir = new File(dirName);
- if (!dir.exists()) {
- throw new JobExecutionException( "Invalid Dir "+ dirName);
- }
- // Use FileFilter to get only XML files
- FileFilter filter = new FileExtensionFileFilter(".xml");
- File[] files = dir.listFiles(filter);
- if (files == null || files.length <= 0) {
- logger.info("No XML files found in " + dir);
- // Return since there were no files
- return;
- }
- // The number of XML files
- int size = files.length;
- // Iterate through the files found
- for (int i = 0; i < size; i++) {
- File file = files[i];
- // Log something interesting about each file.
- File aFile = file.getAbsoluteFile();
- long fileSize = file.length();
- String msg = aFile + " - Size: " + fileSize;
- logger.info(msg);
- }
- }
- }
讓我們來細細看看代碼 3.1 中做了些什么。
當 Quartz 調用 execute() 方法,會傳遞一個 org.quartz.JobExecutionContext 上下文變量,里面封裝有 Quartz 的運行時環境和當前正執行的 job。通過 JobexecutionContext,你可以訪問到調度器的信息,作業和作業上的觸發器的信息,還有更多更多的信息。在代碼 3.1 中,JobExecutionContext 被用來訪問 org.quartz.JobDetail 類,JobDetail 類持有 Job 的詳細信息,包括為 job 實例指定的名稱,job 所屬組,Job 是否被持久化(易失性),和許多其他感興趣的屬性。
JobDetail 又持有一個指向 org.quartz.JobDataMap 的引用。JobDataMap 中有為指定 job 配置的自定義屬性。例如,在代碼 3.1中,我們從 JobDataMap 中獲得欲掃描的目錄名,我們可以在 ScanDirectoryJob 中硬編碼這個目錄名,但是這樣的話我們難以重用這個 Job 來掃描別的目錄了。在后面有一節“編程方式調度一個 Quartz Job”,你將會看到目錄是如何配置到 JobDataMap 的。
execute() 方法中剩下的就是標準 Java 代碼了:獲得目錄名并創建一個 java.io.File 對象。它還對目錄名作為簡單的校驗,確保是一個有效且存在的目錄。接著調用 File 對象的 listFiles() 方法得到目錄下的文件。還創建了一個 java.io.FileFilter 對象作為參數傳遞給 listFiles() 方法。org.quartzbook.cavaness.FileExtensionFileFilter 實現了 java.io.FileFilter 接口,它的作用是過濾掉目錄僅返回 XML 文件。默認情況下,listFiles() 方法是返回目錄中所有內容,不管是文件還是子目錄,所以我們必須過濾一下,因為我們只對 XML 文件感興趣。
注: FileExtensionFileFilter 并非 Quartz 框架的一部分;它是 java.io.FileFilter 的子類,而是 Java 核心的一部分。FileExtensionFileFilter 被創建為我們例子的一部分,用來濾除其他內容而只保留 XML 文件。它相當有用,你可以考慮為你的應用建一系列的文件過濾器,然后在你的 Quartz jobs 中重用。 |
代碼 3.2 是 FileExtensionFileFilter
- package org.cavaness.quartzbook.chapter3;
- import java.io.File;
- import java.io.FileFilter;
- /**
- * A FileFilter that only passes Files of the specified extension.
- * <p>
- * Directories do not pass the filter.
- *
- * @author Chuck Cavaness
- */
- public class FileExtensionFileFilter implements FileFilter {
- private String extension;
- public FileExtensionFileFilter(String extension) {
- this .extension = extension;
- }
- /*
- * Pass the File if it has the extension.
- */
- public boolean accept(File file) {
- // Lowercase the filename for easier comparison
- String lCaseFilename = file.getName().toLowerCase();
- return (file.isFile() &&
- (lCaseFilename.indexOf(extension) > 0 )) ? true : false ;
- }
- }
FileExtensionFileFilter 被用來屏蔽名稱中不含字符串 “.xml” 的文件。它還屏蔽了子目錄--這些子目錄原本會讓 listFiles() 方法正常返回。過濾器提供了一種很便利的方式選擇性的向你的 Quartz 作業提供它能接受的作為輸入的文件。
聲明式之于編程式配置 從其他方面來講,你將要根據具體的需求和功能來選擇用哪一種方式。下一節強調了何時用聲明式何時選擇編程式。因為多數的 Java 行業應用都偏向于聲明的方式,這也是我們所推薦的。 |
在下一節中,我們討論如何為調度器配置 Job 和運行 ScanDirectoryJob。
[譯者注] 翻譯中還得細細考量,那些詞要轉換成中文,那些詞保留成英文。例如,前面的 Job->作業、Application->應用、Task->任務、Scheduler之于調度器;具體下來 Quartz Application 可能比 Quartz 應用好理解,Quart Job 也沒有 Quart 作業讀來生硬。平時不細究,只是閱讀英文資料的話,一眼掠過是不會太在意的,本人翻譯中也有混用,還沒能太明晰。
到目前為止,我們已經創建了一個 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);
- }
- }
- }
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
- package org.cavaness.quartzbook.chapter3;
- import java.util.Date;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.quartz.JobDetail;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerException;
- import org.quartz.Trigger;
- import org.quartz.TriggerUtils;
- import org.quartz.impl.StdSchedulerFactory;
- public class Listing_3_5 {
- static Log logger = LogFactory.getLog(Listing_3_5.class);
- public static void main(String[] args) {
- Listing_3_5 example = new Listing_3_5();
- try {
- // Create a Scheduler and schedule the Job
- Scheduler scheduler = example.createScheduler();
- example.scheduleJob(scheduler);
- // Start the Scheduler running
- scheduler.start();
- logger.info( "Scheduler started at " + new Date() )
- } catch (SchedulerException ex) {
- logger.error(ex);
- }
- }
- /*
- * return an instance of the Scheduler from the factory
- */
- public Scheduler createScheduler() throws SchedulerException {
- return StdSchedulerFactory.getDefaultScheduler();
- }
- // Create and Schedule a ScanDirectoryJob with the Scheduler
- private void scheduleJob(Scheduler scheduler)
- throws SchedulerException {
- // Create a JobDetail for the Job
- JobDetail jobDetail =
- new JobDetail("ScanDirectory",
- Scheduler.DEFAULT_GROUP,
- ScanDirectoryJob.class);
- // Configure the directory to scan
- jobDetail.getJobDataMap().put("SCAN_DIR",
- "c:\\quartz-book\\input");
- // Create a trigger that fires every 10 seconds, forever
- Trigger trigger = TriggerUtils.makeSecondlyTrigger(10);
- trigger.setName("scanTrigger");
- // Start the trigger firing from now
- trigger.setStartTime(new Date());
- // Associate the trigger with the job in the scheduler
- scheduler.scheduleJob(jobDetail, trigger);
- }
- }
上面程序提供了一個理解如何編程式安排一個 Job 很好的例子。代碼首先調用 createScheduler() 方法從 Scheduler 工廠獲取一個 Scheduler 的實例。得到 Scheduler 實例之后,把它傳遞給 schedulerJob() 方法,由它把 job 同 Scheduler 進行關聯。
首先,創建了我們想要運行的 job 的 JobDetail 對象。JobDetail 構造器的參數中包含指派給 job 的名稱,邏輯組名,和實現 org.quartz.Job 接口的全限類名稱。我們可以使用 JobDetail 的別的構造器。
public JobDetail();
public JobDetail(String name, String group, Class jobClass);
public JobDetail(String name, String group, Class jobClass,
boolean volatility, boolean durability, boolean recover);
注
一個 job 在同一個 Scheduler 實例中通過名稱和組名能唯一被標識。假如你增加兩個具體相同名稱和組名的 job,程序會拋出 ObjectAlreadyExistsException 的異常。
在本章前面有說過,JobDetail 扮演著某一 job 定義的角色。它帶有 Job 實例的屬性,能在運行時被所關聯的 Job 訪問到。其中在使用 JobDetail 時,的一個最重要的東西就是 JobDataMap,它被用來存放 Job 實例的狀態和參數。在代碼 3.5 中,待掃描的目錄名稱就是通過 scheduleJob() 方法存入到 JobDataMap 中的。
·理解和使用 Quartz Trigger
Job 只是一個部分而已。注意到代碼 3.5,我們沒有在 JobDetail 對象中為 job 設定執行日期和次數。這是 Quartz trigger 該做的事。顧名思義,Trigger 的責任就是觸發一個 Job 去執行。當用 Scheduler 注冊一個 Job 的時候要創建一個 Trigger 與這個 Job 相關聯。Quartz 提供了四種類型的 Trigger,但其中兩種是最為常用的,它們就是在下面章節中要用到的 SimpleTrigger 和 CronTrigger.
SimpleTrigger 是兩個之中簡單的那個,它主要用來激發單事件的 Job,Trigger 在指定時間激發,并重復 n 次--兩次激發時間之間的延時為 m,然后結束作業。CronTrigger 非常復雜且強大。它是基于通用的公歷,當需要用一種較復雜的時間表去執行一個 Job 時用到。例如,四月至九月的每個星期一、星期三、或星期五的午夜。
為更簡單的使用 Trigger,Quartz 包含了一個工具類,叫做 org.quartz.TriggerUtils. TriggerUtils 提供了許多便捷的方法簡化了構造和配置 trigger. 本章的例子中有用的就是 TriggerUtils 類;SimpleTrigger 和 CronTrigger 會在后面章節中用到。
正如你從代碼3.5中看到的那樣,調用了 TriggerUtils 的方法 makeSecondlyTrigger() 來創建一個每10秒種激發一次的 trigger(實際是由 TriggerUtils 生成了一個 SimpleTrigger 實例,但是我們的代碼并不想知道這些)。我們同樣要給這個 trigger 實例一個名稱并告訴它何時激發相應的 Job;在代碼3.5 中,與之關聯的 Job 會立即啟動,因為由方法 setStartTime() 設定的是當前時間。
代碼 3.5 演示的是如何向 Scheduler 注冊單一 job。假如你有不只一個個 job (你也許就是),你將需要為每一個 job 創建各自的 JobDetail。每一個 JobDetail 必須通過 scheduleJob() 方法一一注冊到 Scheduler 上。
注
回到代碼 3.1 中,我們從代碼中看到要掃描的目錄名屬性是從 JobDataMap 中獲取到的。再看代碼 3.5,你能發現這個屬性是怎么設置的。
如果你想重用了一個 job 類,讓它產生多個實例運行,那么你需要為每個實例都創建一個 JobDetail。例如,假如你想重用 ScanDirectoryJob 讓它檢查兩個不同的目錄,你需要創建并注冊兩個 JobDetail 實例。代碼 3.6 顯示了是如何做的。
代碼 3.6. 運行 ScanDirectoryJob 的多個實例
- package org.cavaness.quartzbook.chapter3;
- import java.util.Date;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.quartz.JobDetail;
- import org.quartz.Scheduler;
- import org.quartz.SchedulerException;
- import org.quartz.Trigger;
- import org.quartz.TriggerUtils;
- import org.quartz.impl.StdSchedulerFactory;
- public class Listing_3_6 {
- static Log logger = LogFactory.getLog(Listing_3_6.class);
- public static void main(String[] args) {
- Listing_3_6 example = new Listing_3_6();
- try {
- // Create a Scheduler and schedule the Job
- Scheduler scheduler = example.createScheduler();
- // Jobs can be scheduled after Scheduler is running
- scheduler.start();
- logger.info("Scheduler started at " + new Date());
- // Schedule the first Job
- example.scheduleJob(scheduler, "ScanDirectory1",
- ScanDirectoryJob.class,
- "c:\\quartz-book\\input", 10);
- // Schedule the second Job
- example.scheduleJob(scheduler, "ScanDirectory2",
- ScanDirectoryJob.class,
- "c:\\quartz-book\\input2", 15);
- } catch (SchedulerException ex) {
- logger.error(ex);
- }
- }
- /*
- * return an instance of the Scheduler from the factory
- */
- public Scheduler createScheduler() throws SchedulerException {
- return StdSchedulerFactory.getDefaultScheduler();
- }
- // Create and Schedule a ScanDirectoryJob with the Scheduler
- private void scheduleJob(Scheduler scheduler, String jobName,
- Class jobClass, String scanDir, int scanInterval)
- throws SchedulerException {
- // Create a JobDetail for the Job
- JobDetail jobDetail =
- new JobDetail(jobName,
- Scheduler.DEFAULT_GROUP, jobClass);
- // Configure the directory to scan
- jobDetail.getJobDataMap().put("SCAN_DIR", scanDir);
- // Trigger that repeats every "scanInterval" secs forever
- Trigger trigger =
- TriggerUtils.makeSecondlyTrigger(scanInterval);
- trigger.setName(jobName + "-Trigger");
- // Start the trigger firing from now
- trigger.setStartTime(new Date());
- // Associate the trigger with the job in the scheduler
- scheduler.scheduleJob(jobDetail, trigger);
- }
- }
代碼 3.6 和代碼 3.5 非常的類似,只存在一點小小的區別。主要的區別是代碼 3.6 中重構了允許多次調用 schedulerJob() 方法。在設置上比如 Job 名稱和掃描間隔名稱通過參數傳。因此從 createScheduler() 方法獲取到 Scheduler 實例后,兩個 job(同一個類) 用不同的參數就被安排到了 Scheduler 上了。(譯者注:當用調 createScheduler() 方法得到 Scheduler 實例后,都還沒有往上注冊 Job,何來兩個 job 呢)。
在 Scheduler 啟動之前還是之后安排 Job 代碼 3.5 中,我們在安排 job 之前就調用了 Scheduler 的 start() 方法。回到代碼 3.5 中,采用了另一種方式:我們是在 job 安排了之后調用了 start() 方法。Job 和 Trigger 可在任何時候在 Scheduler 添加或刪除 (除非是調用了它的 shutdown()方法)。 |
·運行代碼 3.6 中的程序
如果我們執行類 Listing_3_6,會得到類似如下的輸出:
INFO [main] (Listing_3_6.java:35) - Scheduler started at Mon Sep 05 15:12:15 EDT 2005
INFO [QuartzScheduler_Worker-0] ScanDirectory1 fired at Mon Sep 05 15:12:15 EDT 2005
INFO [QuartzScheduler_Worker-0] - c:\quartz-book\input\order-145765.xml - Size: 0
INFO [QuartzScheduler_Worker-0] - ScanDirectory2 fired at Mon Sep 05 15:12:15 EDT 2005
INFO [QuartzScheduler_Worker-0] - No XML files found in c:\quartz-book\input2
INFO [QuartzScheduler_Worker-1] - ScanDirectory1 fired at Mon Sep 05 15:12:25 EDT 2005
INFO [QuartzScheduler_Worker-1] - c:\quartz-book\input\order-145765.xml - Size: 0
INFO [QuartzScheduler_Worker-3] - ScanDirectory2 fired at Mon Sep 05 15:12:30 EDT 2005
INFO [QuartzScheduler_Worker-3] - No XML files found in c:\quartz-book\input2