下面是我們的第一個 Quartz job,它被設計來掃描一個目錄中的文并顯示文件的詳細信息.
當 Quartz 調用 execute() 方法,會傳遞一個 org.quartz.JobExecutionContext 上下文變量,里面封裝有 Quartz 的運行時環境和當前正執行的 Job。通過 JobexecutionContext,你可以訪問到調度器的信息,作業和作業上的觸發器的信息,還有更多更多的信息。在代碼中,JobExecutionContext 被用來訪問 org.quartz.JobDetail 類,JobDetail 類持有 Job 的詳細信息,包括為 Job 實例指定的名稱,Job 所屬組,Job 是否被持久化(易失性),和許多其他感興趣的屬性。
JobDetail 又持有一個指向 org.quartz.JobDataMap 的引用。JobDataMap 中有為指定 Job 配置的自定義屬性。例如,在代碼中我們從 JobDataMap 中獲得欲掃描的目錄名,我們可以在 ScanDirectoryJob 中硬編碼這個目錄名,但是這樣的話我們難以重用這個 Job 來掃描別的目錄了。在后面你將會看到目錄是如何配置到 JobDataMap 的。
execute() 方法中剩下的就是標準 Java 代碼了:獲得目錄名并創建一個 java.io.File 對象。它還對目錄名作為簡單的校驗,確保是一個有效且存在的目錄。接著調用 File 對象的 listFiles() 方法得到目錄下的文件。還創建了一個 java.io.FileFilter 對象作為參數傳遞給 listFiles() 方法。org.quartzbook.cavaness.FileExtensionFileFilter 實現了 java.io.FileFilter 接口,它的作用是過濾掉目錄僅返回 XML 文件。默認情況下,listFiles() 方法是返回目錄中所有內容,不管是文件還是子目錄,所以我們必須過濾一下,因為我們只對 XML 文件感興趣。
FileExtensionFileFilter 被用來屏蔽名稱中不含字符串 “.xml” 的文件。它還屏蔽了子目錄--這些子目錄原本會讓 listFiles() 方法正常返回。過濾器提供了一種很便利的方式選擇性的向你的 Quartz 作業提供它能接受的作為輸入的文件.
package com.vista.quartz;
import java.io.File;
import java.io.FileFilter;
public class FileExtensionFileFilter implements FileFilter
{
private String extension;//文件后綴
public FileExtensionFileFilter(String extension)
{
this.extension = 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 ;
}
}
到目前為止,我們已經創建了一個 Quartz job,但還沒有決定怎么處置它--明顯地,我們需以某種方式為這個 Job 設置一個運行時間表。時間表可以是一次性的事件,或者我們可能會安裝它在除周日之外的每個午夜執行。你即刻將會看到,Quartz Schduler 是框架的心臟與靈魂。所有的 Job 都通過 Schduler 注冊;必要時,Scheduler 也會創建 Job 類的實例,并執行實例的 execute() 方法。
·編程式安排一個 Quartz Job
所有的要 Quartz 來執行的作業必須通過調度器來注冊。大多情況下,這會在調度器啟動前做好。正如前面說過,這一操作也提供了聲明式與編程式兩種實現途徑的選擇。
因為每一個 Job 都必須用 Scheduler 來注冊,所以先定義一個 JobDetail,并關聯到這個 Scheduler 實例。
下面的程序提供了一個理解如何編程式安排一個 Job 很好的例子。代碼首先調用 createScheduler() 方法從 Scheduler 工廠獲取一個 Scheduler 的實例。得到 Scheduler 實例之后,把它傳遞給 schedulerJob() 方法,由它把 Job 同 Scheduler 進行關聯。
首先,創建了我們想要運行的 Job 的 JobDetail 對象。JobDetail 構造器的參數中包含指派給 Job 的名稱,邏輯組名,和實現 org.quartz.Job 接口的全限類名稱。我們可以使用 JobDetail 的別的構造器。
在前面有說過,JobDetail 扮演著某一 Job 定義的角色。它帶有 Job 實例的屬性,能在運行時被所關聯的 Job 訪問到。其中在使用 JobDetail 時,的一個最重要的東西就是 JobDataMap,它被用來存放 Job 實例的狀態和參數。在代碼中,待掃描的目錄名稱就是通過 scheduleJob() 方法存入到 JobDataMap 中的。
Job 只是一個部分而已。注意我們沒有在 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 會在后面用到。
正如你看到的那樣,調用了 TriggerUtils 的方法 makeSecondlyTrigger() 來創建一個每10秒種激發一次的 trigger(實際是由 TriggerUtils 生成了一個 SimpleTrigger 實例,但是我們的代碼并不想知道這些)。我們同樣要給這個 trigger 實例一個名稱并告訴它何時激發相應的 Job;與之關聯的 Job 會立即啟動,因為由方法 setStartTime() 設定的是當前時間
package com.vista.quartz;
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 SimpleScheduler
{
static Log logger = LogFactory.getLog(SimpleScheduler.class);
public static void main(String[] args)
{
SimpleScheduler simple = new SimpleScheduler();
try
{
// Create a Scheduler and schedule the Job
Scheduler scheduler = simple.createScheduler();
simple.scheduleJob(scheduler);
// Start the Scheduler running
scheduler.start();
logger.info( "Scheduler started at " + new Date());
} catch (SchedulerException ex) {
logger.error(ex);
}
}
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","D:\\Tomcat\\conf"); //set the JobDataMap that is associated with the Job.
// Create a trigger that fires every 10 seconds, forever
Trigger trigger = TriggerUtils.makeSecondlyTrigger(10);//每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 (你也許就是),你將需要為每一個 Job 創建各自的 JobDetail。每一個 JobDetail 必須通過 scheduleJob() 方法一一注冊到 Scheduler 上。而如果你想重用了一個 Job 類,讓它產生多個實例運行,那么你需要為每個實例都創建一個 JobDetail。例如,假如你想重用 ScanDirectoryJob 讓它檢查兩個不同的目錄,你需要創建并注冊兩個 JobDetail 實例
package com.vista.quartz;
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 SimpleScheduler
{
static Log logger = LogFactory.getLog(SimpleScheduler.class);
public static void main(String[] args)
{
SimpleScheduler simple = new SimpleScheduler();
try
{
// Create a Scheduler and schedule the Job
Scheduler scheduler = simple.createScheduler();
// Jobs can be scheduled after Scheduler is running
scheduler.start();
logger.info("Scheduler started at " + new Date());
// Schedule the first Job
simple.scheduleJob(scheduler, "ScanDirectory1",ScanDirectoryJob.class,"D:\\conf1", 10);
// Schedule the second Job
simple.scheduleJob(scheduler, "ScanDirectory2",ScanDirectoryJob.class,"D:\\conf2 ", 15);
}
catch (SchedulerException ex)
{
logger.error(ex);
}
}
public Scheduler createScheduler() throws SchedulerException
{//創建調度器
return StdSchedulerFactory.getDefaultScheduler();
}
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);
}
}