·创建一个QuartzJob 类
每一个QuartzJob 必须有一个实现了org.quartz.Job接口的具体类。这个接口仅有一个要你在Job中实现的方法,execute(),方法execute()的原型如下:
public voidexecute(JobExecutionContext context) throwsJobExecutionException;
当Quartz调度器确定到时间要激发一个Job的时候,它就会生成一个 Job实例,并调用这个实例的execute()方法。调度器只管调用execute()方法,而不关心执行的结果,除了在作业执行中出问题抛出的org.quartz.JobExecutionException异常。
下面是我们的第一个Quartzjob,它被设计来扫描一个目录中的文并显示文件的详细信息。
package com.vista.quartz;
import java.io.File;
import java.io.FileFilter;
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;
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");
//只统计xml文件
File[] files = dir.listFiles(filter);
if (files == null || files.length <= 0)
{//目录下没有xml文件
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);//记录下文件的路径和大小
}
}
}
当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 ;
}
}
到目前为止,我们已经创建了一个Quartzjob,但还没有决定怎么处置它--明显地,我们需以某种方式为这个Job设置一个运行时间表。时间表可以是一次性的事件,或者我们可能会安装它在除周日之外的每个午夜执行。你即刻将会看到,QuartzSchduler 是框架的心脏与灵魂。所有的Job都通过Schduler注册;必要时,Scheduler也会创建Job类的实例,并执行实例的execute() 方法。
·编程式安排一个QuartzJob
所有的要 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 设定执行日期和次数。这是QuartzTrigger 该做的事。顾名思义,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);
}
}
作者:洞庭散人
出处:http://phinecos.cnblogs.com/
本博客遵从Creative Commons Attribution 3.0License,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。