Quartz 框架快速入门(一)

来源:互联网 发布:怎样建立切片软件 编辑:程序博客网 时间:2024/05/21 10:01

      创建一个Java工程,引入几个JAR到工程中才能成功构建它们。首先,你需要Quartz的二进制版本,包的名字是quartz-<version>.jarQuartz还需要几个第三方库;这依赖于你要用到框架的什么功能而定,CommonsDigester 库可以在<QUARTZ_HOME>/lib/core<QUARTZ_HOME>/lib/optional目录中找到。如果出现java.lang.NoClassDefFoundError:javax/transaction/UserTransaction的错误,解决办法是:引入jta.jar包,这个包在quartz-1.6.0/lib/build下。

·创建一个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 = 0< 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进行关联。

首先,创建了我们想要运行的JobJobDetail 对象。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是两个之中简单的那个,它主要用来激发单事件的JobTrigger 在指定时间激发,并重复 n --两次激发时间之间的延时为 m,然后结束作业。CronTrigger非常复杂且强大。它是基于通用的公历,当需要用一种较复杂的时间表去执行一个Job时用到。例如,四月至九月的每个星期一、星期三、或星期五的午夜。

为更简单的使用 TriggerQuartz 包含了一个工具类,叫做 org.quartz.TriggerUtils. TriggerUtils 提供了许多便捷的方法简化了构造和配置trigger.本文的例子中有用的就是TriggerUtils 类;SimpleTriggerCronTrigger 会在后面用到。

正如你看到的那样,调用了 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 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 ScanDirectoryJob with the Scheduler       
    private void scheduleJob(Scheduler scheduler) throws SchedulerException 
          
         
// Create 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 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 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 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。
原创粉丝点击