`
FengShen_Xia
  • 浏览: 279326 次
  • 性别: Icon_minigender_1
  • 来自: 东方水城
社区版块
存档分类
最新评论

Quartz 定时器

阅读更多

这篇文章是英文教程的中文翻译,有些认为暂时使用不到的特性有省略,英文文档参见http://www.opensymphony.com/quartz/wikidocs/TutorialLesson1.html


如何使用
使用QUARTZ调试程序之前,必须使用SchedlerFactory实例化Scheduler。一旦实例化Scheduler后可以启动或者停止,需要注意的是一旦Scheduler关闭,必须重新实例化后才能够重启。任务只有在Scheduler启动后才会执行。

 

下面的代码片断实例化并启动Scheduler,然后执行一个任务。

SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();    
Scheduler sched = schedFact.getScheduler();    
sched.start();    
JobDetail jobDetail = new JobDetail("myJob", null, DumbJob.class);    
Trigger trigger = TriggerUtils.makeHourlyTrigger(); // fire every hour    
trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));    
trigger.setName("myTrigger");    
sched.scheduleJob(jobDetail, trigger);   

  

任务/触发器
 

要定义一个任务,只需要实现Job接口即可,Job接口如下:

package org.quartz;public interface Job {  public void execute(JobExecutionContext context)       
      throws JobExecutionException;       
}   

  
当任务被触发时将调用execute方法,JobExecutionContext 参数提供关于任务的运行时环境,包括一个Scheduler的引用,触发这个任务的触发器的引用,任务的JobDetail实例和一些别的信息。

 

JobDetail 对象在添加任务到Scheduler时创建,这个对象和*JobDataMap* 都用来保存Job实例的状态信息。

Trigger 用来触发任务。要计划一个任务,需要实例化一个触发器并设置相关的属性,触发器也有一个关联的JobDataMap用来传递参数给指定的任务。Quartz提供几个不同的触发器实例,比较常用的是SimpleTrigger和CronTrigger。

 

如果需要在一个指定的时间,或者指定的时间后以一个指定的间隔对一个任务重复执行多次,使用SimpleTrigger。如果需要基于日历安排任务,使用CronTrigger,比如每个星期五中午。

 

很多任务调用器没有分离任务和触发器,Quartz这样做有很多好处。比如一个任务可以和多个触发器关联,可以更改或替换一个触发器,而不必重新定义任务。

 

任务和触发器都有唯一标识名称,也可以进行分组,在一个组中任务和触发器的名称必须是唯一的,这意味着任务和触发器是使用名称+组名唯一标识的。如果不指定组名,相当于使用缺省的组名: Scheduler.DEFAULT_GROUP 。

 

任务
以前的Quartz要求具体的Job实现类通过get/set方法传递数据,现在使用JobDetail类来传递数据。

 

我们先来看一个实例:

JobDetail jobDetail = new JobDetail("myJob", // job name                                
                                    sched.DEFAULT_GROUP, // job group (you can also specify 'null' to use the default group)    
                                    DumbJob.class);               // the java class to executeTrigger trigger = TriggerUtils.makeDailyTrigger(8, 30);    
trigger.setStartTime(new Date());    
trigger.setName("myTrigger");sched.scheduleJob(jobDetail, trigger);  

  
如下是DumbJob类的代码:

public class DumbJob implements Job {    
       public DumbJob() {    
       }    
       public void execute(JobExecutionContext context)    
           throws JobExecutionException    
       {    
           System.err.println("DumbJob is executing.");    
       }    
   }   

 
注意在添加一个任务时,传递了一个JobDetail实例作为参数,构建这个JobDetail实例时需要一个任务类参数。每次调用程序执行任务时,创建一个新的任务类实例并执行其execute方法,但是这种方法有一些限制,首先是所有的任务实现必须提供一个无参数的构造函数,还有就是任务实现不应该包含成员字段,因为在每次执行后这些值都会被消除。

 

那么应该如何给一个任务提供属性或者配置呢?如何在任务的不同执行过程中保存或跟踪任务的状态呢?这是通过JobDetail的JobDataMap来实现。

 

JobDataMap
JobDataMap可以用来保存任何需要传递给任务实例的对象(这些对象要求是可序列化的),JobDataMap是java的Map接口的实现,添加了一些便利方法,下面的代码片断描述了如何使用JobDataMap保存数据:

jobDetail.getJobDataMap().put("jobSays", "Hello World!");    
jobDetail.getJobDataMap().put("myFloatValue", 3.141f);    
jobDetail.getJobDataMap().put("myStateData", new ArrayList());  

  
下面的示例描述了如何在任务执行过程中从JobDataMap获取数据:

public class DumbJob implements Job {           
       public DumbJob() {    
       }           
   
       public void execute(JobExecutionContext context)    
           throws JobExecutionException    
       {    
           String instName = context.getJobDetail().getName();    
           String instGroup = context.getJobDetail().getGroup();               
          JobDataMap dataMap = context.getJobDetail().getJobDataMap();               
           String jobSays = dataMap.getString("jobSays");    
           float myFloatValue = dataMap.getFloat("myFloatValue");    
           ArrayList state = (ArrayList)dataMap.get("myStateData");    
           state.add(new Date());               
           System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);    
       }    
   }    


如果使用可持久化的JobStore(随后会有讨论),需要小心决定将JobDataMap保存在什么地方,因为JobDataMap对象中保存的对象是可序列化的,因此可能会遇到类版本问题。

 

有状态/无状态
触发器也可以使用JobDataMap保存数据。当需要使用多个触发器重用保存在Scheduler中的单个任务实例时,并且针对每个触发器希望提供任务不同的数据时,这是比较有用的。

 

JobDataMap在任务执行过程中,可以在JobExecutionContext中找到,这里的JobDataMap是JobDetail中的JobDataMap和触发器中的JobDataMap合并的结果,如果遇到命名相同的元素,后者会重写前者。

 

如下是从JobExecutionContext中获取JobDataMap的代码片断:

public class DumbJob implements Job {              
    public DumbJob() {    
    }             
    public void execute(JobExecutionContext context)    
                throws JobExecutionException    
     {    
                String instName = context.getJobDetail().getName();    
                String instGroup = context.getJobDetail().getGroup();                    
                JobDataMap dataMap = context.getJobDataMap();    // Note the difference from the previous example                    
                 String jobSays = dataMap.getString("jobSays");    
                float myFloatValue = dataMap.getFloat("myFloatValue");    
                ArrayList state = (ArrayList)dataMap.get("myStateData");    
                state.add(new Date());                    
                 System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);    
          }    
    }   
 

 

有状态任务
任务可以被定义成有状态或无状态的,无状态任务仅仅通过JobDataMap传递数据,这意味着每次任务执行后对JobDataMap的改变都会丢失,而有状态任务恰恰相反,每次任务执行后JobDataMap都被恢复。有状态任务不能并发执行。

实现*StatefulJob*接口的任务是有状态的

 

任务属性
下面是通过JobDetail对象定义的一些任务属性:

Durability - 如果这个值为false,每次任务没有活动的触发器关联时都将从Scheduler中删除。
Volatility - 如果任务是暂态的,在每次重启Scheduler时将不会被持久化RequestsRecovery - 如果任务是"requests recovery",当他在Scheduler关闭的时间正在执行时,当Scheduler再次启动时将再次被执行。

JobListeners - 任务可以添加多个JobListener实例,当任务执行时,这些监听器将接收到通知。

JobExecutionException - Job的execute方法只能抛出JobExecutionException,这就意味着通常你需要try-catch方法中的所有代码。详细信息可以参考JAVADOC。

 

触发器
Calendars
Quartz Calendar 对象 (不是 java.util.Calendar对象) 可以和触发器关联,当需要从触发器中排除一些时间时,Calendar是比较有用的。比如你希望创建一个触发器,在每个星期三的上午九点激活一个任务,然后通过加一个Calendar实例排除所有的节假日。Calendar接口如下:

package org.quartz;         
public interface Calendar     
{                 
    public boolean isTimeIncluded(long timeStamp);     
    public long getNextIncludedTime(long timeStamp);         
}  

  
注意这些方法的参数单位是微秒,这意味着Calendar可以精确到微秒,但是通常我们只关心天,Quartz提供一个org.quartz.impl.HolidayCalendar类用来简化Calendar的使用。

 

Calendar必须使用Scheduler的addCalendar方法进行注册。如果使用HolidayCalendar,实例化后应该调用addExcludedDate(Date date)添加那些需要排除的日期,同一个Calendar可以用于多个触发器。

 

HolidayCalendar cal = new HolidayCalendar();    
cal.addExcludedDate( someDate );        
sched.addCalendar("myHolidays", cal, false);        
   
Trigger trigger = TriggerUtils.makeHourlyTrigger(); // fire every one hour interval    
trigger.setStartTime(TriggerUtils.getEvenHourDate(new Date()));    // start on the next even hour    
trigger.setName("myTrigger1");       
trigger.setCalendarName("myHolidays");    // .. schedule job with trigger        
   
Trigger trigger2 = TriggerUtils.makeDailyTrigger(8, 0); // fire every day at 08:00    
trigger.setStartTime(new Date()); // begin immediately    
trigger2.setName("myTrigger2");       
trigger2.setCalendarName("myHolidays");    // .. schedule job with trigger2   

TriggerUtils
TriggerUtils 类包含一些创建触发器和日期的便利方法。使用这个类可以很容易的创建基于分钟,小时,天,星期,月的触发器。

 

TriggerListener
触发器也可以注册监听器,监听器必须实现*TriggerListener* 接口。

 

SimpleTrigger
如果需要计划一个任务在指定的时间执行,或者在指定的时间后以指定的间隔连续执行多次,比如希望在2005年1月12号上午11:22:54开始执行一个任务,在这之后每隔20分钟执行一次,共执行一次,这种情况下可以使用SimpleTrigger。

SimpleTrigger包含几个属性:开始时间,结束时间,重复次数和间隔。

 

重复次数可以是大于等于0,或者是常量值SimpleTrigger.REPEAT_INDEFINITELY,间隔必须大于等于0的长整数,单位是微秒。如果间隔为0表示并发执行重复次数。

 

如果不熟悉java.util.Calendar类,可能经常需要根据开始时间计算触发时间,org.quartz.helpers.TriggerUtils 可以帮助完成这些任务。

 

结束时间属性重写重复次数属性。如果希望创建一个触发器,每隔10秒执行一次,直到一个指定的时间,可以简单的指定结束时间, 重复次数值为REPEAT_INDEFINITELY。

 

SimpleTrigger有几个构造函数,下面是其中一个:

public SimpleTrigger(String name,    
                       String group,    
                       Date startTime,    
                       Date endTime,    
                       int repeatCount,    
                       long repeatInterval)    

 

创建一个10秒钟后只执行一次的触发器:

long startTime = System.currentTimeMillis() + 10000L;    
   
SimpleTrigger trigger = new SimpleTrigger("myTrigger",    
                                            null,    
                                            new Date(startTime),    
                                            null,    
                                            0,    
                                            0L);    

 

创建一个每隔60秒重复执行的触发器:

SimpleTrigger trigger = new SimpleTrigger("myTrigger",    
                                            null,    
                                            new Date(),    
                                            null,    
                                            SimpleTrigger.REPEAT_INDEFINITELY,    
                                            60L * 1000L);   


创建一个40秒后开始执行,每隔10秒执行一次的触发器:

long endTime = System.currentTimeMillis() + 40000L;    
   
SimpleTrigger trigger = new SimpleTrigger("myTrigger",    
                                            "myGroup",    
                                            new Date(),    
                                            new Date(endTime),    
                                            SimpleTrigger.REPEAT_INDEFINITELY,    
                                            10L * 1000L);    

 创建一个触发器,在2002年3月17日开始执行,重复5次,每次间隔为30秒:

 

java.util.Calendar cal = new java.util.GregorianCalendar(2002, cal.MARCH, 17);    
  cal.set(cal.HOUR, 10);    
  cal.set(cal.MINUTE, 30);    
  cal.set(cal.SECOND, 0);    
  cal.set(cal.MILLISECOND, 0);  Data startTime = cal.getTime()  SimpleTrigger trigger = new SimpleTrigger("myTrigger",    
                                            null,    
                                            startTime,    
                                            null,    
                                            5,    
                                            30L * 1000L);   

 

CronTrigger

如果需要基于日历指定触发器,可以使用CronTrigger。使用CronTrigger可以实现类似的触发器,比如:每个星期五的下午。比如每个星期一,三和五的上午9点到10点之间每隔5分钟。

 

CronTrigger也有一个开始时间和结束时间属性,用来指定什么时候任务开始和结束。

 

Cron表达式:*Cron*表达式用来配置CronTrigger。Cron表达式是一个由七个部分组成的字符串,这七个部分用空隔进行分隔:

       Seconds 
       Minutes
       Hours
       Day-of-Month (月内日期)
       Month
       Day-of-Week (周内日期)
       Year (可选字段)

 

       每个字段都有一些有效值。比如秒和分可以取值0-59,小时可以取值0-23。Day-of-Month可以取值0-31,需要注意一个月有多少天。 月可以取值0-11,或者通过使用JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 和 DEC。 Days-of-Week可以取值1-7(1==Sunday)或者SUN, MON, TUE, WED, THU, FRI 和SAT。

 

'/' 字符可以用来指定增量,比如如果指定Minute字段为"0/15"表示在第0分钟启动,每隔15分钟的间隔;"3/20"表示每三分钟启动,每隔20分钟的间隔。

 

       '?' 字符可以在day-of-month和day-of-week 字段中使用。问号表示这个字段不包含具体值。所以,如果指定月内日期,可以在周内日期字段中插入“?”,表示周内日期值无关紧要。

 

'L'字符可以在day-of-month和day-of-week 字段中使用,这个字符表示最后一个的意思。比如在day-of-month字段中表示这个月的最后一天,如果在day-of-week字段表示"7"或者"SAT",但是如果在day-of-week字段L在另一个值后面,意味着这个月的最后XXX天,比如"6L"表示这个月的最后一个星期五。使用这个字符,不能指定列表,范围值。

 

'W'字符用来指定离指定天最近的星期XXX,比如如果day-of-month字段值为"15W",表示离这个月15号最近的一个

weekday。

 

'#'字符用来表示这个月的第几个XXX,比如day-of-week字段的"6#3"表示这个月的第三个星期五。

 

 '*'字符表示是通配字符,表示该字段可以接受任何可能的值,比如Day-Of-Week字段的*表示每天。

 

下面是一些示例:
创建一个每五分钟激活一次的触发器: 

"0 0/5 * * * ?"  

 创建一个触发器在当前分钟的第10秒后,每五分钟执行一次,比如上午10:00:10 am,上午10:05:10:

"10 0/5 * * * ?"    

 创建一个触发器,在每个星期三和星期五的10:30, 11:30, 12:30, 和13:30执行。

"0 30 10-13 ? * WED,FRI" 

    创建一个触发器,在每个月的第5天和第20天的上午8点到10点执行,每隔半小时执行一次,注意上午10:00不会执行:

"0 0/30 8-9 5,20 * ?"  

  
监听器

基于触发器的监听器接口如下:

public interface TriggerListener {    
   
    public String getName();    
   
    public void triggerFired(Trigger trigger, JobExecutionContext context);    
   
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);    
   
    public void triggerMisfired(Trigger trigger);    
   
    public void triggerComplete(Trigger trigger, JobExecutionContext context,    
            int triggerInstructionCode);    
}    


基于任务的监听器接口如下:

 

public interface JobListener {    
   
    public String getName();    
   
    public void jobToBeExecuted(JobExecutionContext context);    
   
    public void jobExecutionVetoed(JobExecutionContext context);    
   
    public void jobWasExecuted(JobExecutionContext context,    
            JobExecutionException jobException);    
   
}    

 

注册监听器
要创建一个监听器,只需要实现相应的接口就可以了。监听器需要在Scheduler中注册,监听器可以被注册为全局的或者本地的,注册监听器时必须指定一个名字,或者监听器本身的getName方法返回一个值。

 

scheduler.addGlobalJobListener(myJobListener);    
or    
scheduler.addJobListener(myJobListener);    
分享到:
评论

相关推荐

    Quartz定时器介绍与简单使用

    ### Quartz定时器介绍与简单使用 #### 1.1 Quartz介绍 Quartz 是一款功能强大的开源任务调度框架,它完全采用 Java 编写而成。该框架允许开发人员以灵活的方式定义作业及其触发规则,从而实现对任务的定时调度。...

    quartz定时器源码jar包下载

    作为一个专业的IT行业大师,我很高兴为你解析Quartz定时器的核心概念、功能以及如何通过源码学习。 Quartz定时器允许开发者创建、调度和管理任务,这些任务可以是简单的函数调用或者复杂的业务流程。它支持多种调度...

    Spring Quartz 定时器示例(Web工程版)

    Spring Quartz 定时器示例(Web工程版),欢迎下载。

    Quartz定时器从入门到进阶

    Quartz定时器是一个开源的作业调度框架,专为J2SE和J2EE应用程序设计,完全用Java编写。它的核心优势在于提供强大的灵活性和简单性,使得开发者可以轻松创建简单的或复杂的任务调度。Quartz支持多种特性,如数据库...

    quartz定时器api

    Quartz定时器API是Java平台上一个强大的作业调度框架,它被广泛用于构建自动化任务和后台作业,例如数据备份、报表生成、系统维护等。Quartz提供了丰富的API来创建、管理和控制作业(Jobs)和触发器(Triggers),...

    Quartz定时器事例

    下面,我们将深入探讨Quartz定时器的工作原理、配置、API使用以及在实际项目中的应用案例。 1. **Quartz简介** - Quartz是一个基于JDBC存储的可扩展的作业调度框架,能够用于执行计划性的任务。 - 它支持复杂的...

    java Spring OpenSymphony的Quartz定时器的时间设置

    在Java Spring框架中,开发者有多种选择来实现定时任务的功能,其中最为流行的两种方式分别是使用Java自带的`Timer`类以及OpenSymphony的Quartz定时器。本文将重点探讨Quartz定时器的配置与使用,尤其是其时间设置的...

    一个简单的quartz定时器的demo

    这个"一个简单的quartz定时器的demo"是展示如何在项目中集成和使用Quartz的基本步骤,包括创建任务、配置调度器以及管理任务的生命周期。 首先,Quartz的核心组件包括Scheduler(调度器)、Job(任务)和Trigger...

    Quartz定时器表.sql

    Quartz定时器表 执行语句 方便部署处理数据

    spring boot集成quartz定时器

    本文将详细讲解如何在Spring Boot项目中集成Quartz定时器,以及如何利用Spring的依赖注入特性来实现Job。 一、集成Quartz定时器 1. 添加依赖:首先,你需要在Spring Boot项目的`pom.xml`或`build.gradle`文件中...

    Spring Quartz定时器的jar包

    Spring Quartz定时器是Java开发中常用的一个任务调度框架,它结合了Spring框架的强大功能与Quartz的灵活性,使得开发者能够方便地在应用中实现定时任务。在这个压缩包中,包含了三个核心的jar文件:`quartz-all-...

    Quartz定时器,表达式自动生成工具

    Quartz定时器是一款广泛应用于Java开发中的开源任务调度框架,其功能强大且灵活,能够帮助开发者轻松实现定时任务的管理。在Java应用中,我们常常需要执行一些周期性的任务,如数据备份、清理缓存或者发送邮件等,而...

    [Quartz]Quartz定时器的j2ee系统使用

    Quartz的Hibernate模型 博文链接:https://xmkevinchen.iteye.com/blog/196392

    quartz定时器2.2.1JAR包

    Quartz定时器是一款开源的、功能强大的作业调度框架,它为Java应用程序提供了精确且可扩展的任务调度能力。在Java世界中,Quartz以其灵活性、稳定性和广泛的社区支持而备受推崇。2.2.1版本是Quartz的一个稳定版本,...

    一个基础的Quartz定时器案例

    在这个基础的Quartz定时器案例中,我们将探讨如何使用Quartz API来创建、配置和执行定时任务。 首先,Quartz的核心组件包括Job(任务)、Trigger(触发器)和Scheduler(调度器)。Job是实际需要执行的任务,...

    quartz定时器配置与jar包

    本资料包将详细介绍如何在Spring框架中配置和使用Quartz定时器,并涉及到cron表达式的使用。 一、Quartz简介 Quartz是一个完全由Java编写的作业调度框架,能够精确地调度任务,支持简单或复杂的调度需求。Quartz的...

    quartz 定时器

    #### 一、Quartz定时器概述 ##### 特点: 1. **灵活性**:Quartz能嵌入到任何独立的应用中运行,无论是桌面应用程序还是服务器端应用。 2. **事务支持**:Quartz能够在应用服务器或Servlet容器中实例化,并且能够...

    quartz定时器不依赖任何框架

    Quartz定时器是一款强大且灵活的开源作业调度框架,它允许开发者在Java应用程序中安排复杂的任务执行。Quartz不依赖任何特定的Web或应用服务器框架,因此可以独立使用,这正是"quartz定时器不依赖任何框架"这个主题...

    quartz定时器mysql 脚本

    quartz定时器mysql的脚本,如果需要定时器持久化到数据库,可以使用

    简单实现Spring Quartz定时器

    Spring Quartz定时器是一种在Java应用中实现定时任务的流行框架,它允许开发者精确地调度任务执行。本篇文章将深入探讨如何在Spring框架中简单实现Quartz定时器,并结合源码和工具来帮助理解其工作原理。 首先,让...

Global site tag (gtag.js) - Google Analytics