`
dwj147258
  • 浏览: 192184 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Quartz入门

阅读更多

入门简介:

基本上任何公司都会用到调度这个功能, 比如我们公司需要定期执行调度生成报表, 或者比如博客什么的定时更新之类的,都可以靠Quartz来完成。正如官网所说,小到独立应用大到大型电子商务网站, Quartz都能胜任。

 

 

Quartz体系结构:

明白Quartz怎么用,首先要了解Scheduler(调度器)Job(任务)Trigger(触发器)这3个核心的概念。

 

1. Job: 是一个接口,只定义一个方法execute(JobExecutionContext context),在实现接口的execute方法中编写所需要定时执行的Job(任务), JobExecutionContext类提供了调度应用的一些信息。Job运行时的信息保存在JobDataMap实例中;

 

2. JobDetail: Quartz每次调度Job时, 都重新创建一个Job实例, 所以它不直接接受一个Job的实例,相反它接收一个Job实现类(JobDetail:描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息),以便运行时通过newInstance()的反射机制实例化Job。 

 

3. Trigger: 是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的15:00~16:00执行调度等;

  Cron表达式的格式:秒 分 时 日 月 周 年(可选)。
               字段名                 允许的值                        允许的特殊字符  
               秒                         0-59                               , - * /  
               分                         0-59                               , - * /  
               小时                   0-23                                 , - * /  
               日                         1-31                               , - * ? / L W C  
               月                         1-12 or JAN-DEC           , - * /  
               周几                     1-7 or SUN-SAT             , - * ? / L C #      SUN, MON, TUE, WED, THU, FRI and SAT
               年 (可选字段)     empty, 1970-2099            , - * /

               “?”字符:表示不确定的值
               “,”字符:指定数个值
               “-”字符:指定一个值的范围
               “/”字符:指定一个值的增加幅度。n/m表示从n开始,每次增加m
               “L”字符:用在日表示一个月中的最后一天,用在周表示该月最后一个星期X
               “W”字符:指定离给定日期最近的工作日(周一到周五)
               “#”字符:表示该月第几个周X。6#3表示该月第3个周五


         Cron表达式范例:
                 每隔5秒执行一次:*/5 * * * * ?
                 每隔1分钟执行一次:0 */1 * * * ?
                 每天23点执行一次:0 0 23 * * ?
                 每天凌晨1点执行一次:0 0 1 * * ?
                 每月1号凌晨1点执行一次:0 0 1 1 * ?
                 每月最后一天23点执行一次:0 0 23 L * ?
                 每周星期天凌晨1点实行一次:0 0 1 ? * L
                 在26分、29分、33分执行一次:0 26,29,33 * * * ?
                 每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?

 

4. Calendar:org.quartz.Calendar和java.util.Calendar不同, 它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。 一个Trigger可以和多个Calendar关联, 以便排除或包含某些时间点。

假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。针对不同时间段类型,Quartz在org.quartz.impl.calendar包下提供了若干个Calendar的实现类,如AnnualCalendar、MonthlyCalendar、WeeklyCalendar分别针对每年、每月和每周进行定义;

 

5. Scheduler: 代表一个Quartz的独立运行容器, Trigger和JobDetail可以注册到Scheduler中, 两者在Scheduler中拥有各自的组及名称, 组及名称是Scheduler查找定位容器中某一对象的依据, Trigger的组及名称必须唯一, JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法, 允许外部通过组及名称访问和控制容器中Trigger和JobDetail。

Scheduler可以将Trigger绑定到某一JobDetail中, 这样当Trigger触发时, 对应的Job就被执行。一个Job可以对应多个Trigger, 但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例;

 

6. ThreadPool: Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。
Job有一个StatefulJob子接口,代表有状态的任务,该接口是一个没有方法的标签接口,其目的是让Quartz知道任务的类型,以便采用不同的执行方案。无状态任务在执行时拥有自己的JobDataMap拷贝,对JobDataMap的更改不会影响下次的执行。而有状态任务共享共享同一个JobDataMap实例,每次任务执行对JobDataMap所做的更改会保存下来,后面的执行可以看到这个更改,也即每次执行任务后都会对后面的执行发生影响。
正因为这个原因,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行,这意味着如果前次的StatefulJob还没有执行完毕,下一次的任务将阻塞等待,直到前次任务执行完毕。有状态任务比无状态任务需要考虑更多的因素,程序往往拥有更高的复杂度,因此除非必要,应该尽量使用无状态的Job。
如果Quartz使用了数据库持久化任务调度信息,无状态的JobDataMap仅会在Scheduler注册任务时保持一次,而有状态任务对应的JobDataMap在每次执行任务后都会进行保存。
Trigger自身也可以拥有一个JobDataMap,其关联的Job可以通过JobExecutionContext#getTrigger().getJobDataMap()获取Trigger中的JobDataMap。不管是有状态还是无状态的任务,在任务执行期间对Trigger的JobDataMap所做的更改都不会进行持久,也即不会对下次的执行产生影响。

Quartz拥有完善的事件和监听体系,大部分组件都拥有事件,如任务执行前事件、任务执行后事件、触发器触发前事件、触发后事件、调度器开始事件、关闭事件等等,可以注册相应的监听器处理感兴趣的事件。 

 

下图描述了Scheduler的内部组件结构,SchedulerContext提供Scheduler全局可见的上下文信息,每一个任务都对应一个JobDataMap,虚线表达的JobDataMap表示对应有状态的任务:


 

 

废话不多说, 上代码:

 

1. 最简单的Job代码(就打印Hello Quartz !):

 

[java] view plain copy
 
 print?
  1. package com.wenniuwuren.quartz;  
  2.    
  3. import org.quartz.Job;  
  4. import org.quartz.JobExecutionContext;  
  5. import org.quartz.JobExecutionException;  
  6.    
  7. public class HelloQuartz  implements Job {  
  8.    
  9.     public void execute(JobExecutionContext arg0) throws JobExecutionException {  
  10.         System.out.println("Hello Quartz !");                 
  11.     }         
  12. }  


2. 设置触发器

 

 

[java] view plain copy
 
 print?
  1. package com.wenniuwuren.quartz;  
  2.     
  3. import org.quartz.CronScheduleBuilder;    
  4. import org.quartz.JobBuilder;    
  5. import org.quartz.JobDetail;    
  6. import org.quartz.Scheduler;    
  7. import org.quartz.SchedulerException;  
  8. import org.quartz.SchedulerFactory;    
  9. import org.quartz.SimpleScheduleBuilder;  
  10. import org.quartz.Trigger;    
  11. import org.quartz.TriggerBuilder;    
  12. import org.quartz.impl.StdSchedulerFactory;    
  13.     
  14. public class SchedulerTest {    
  15.    public static void main(String[] args) throws InterruptedException {    
  16.        
  17.        //通过schedulerFactory获取一个调度器    
  18.        SchedulerFactory schedulerfactory = new StdSchedulerFactory();    
  19.        Scheduler scheduler=null;    
  20.        try{    
  21.            // 通过schedulerFactory获取一个调度器    
  22.            scheduler = schedulerfactory.getScheduler();    
  23.                
  24.             // 创建jobDetail实例,绑定Job实现类    
  25.             // 指明job的名称,所在组的名称,以及绑定job类    
  26.            JobDetail job = JobBuilder.newJob(HelloQuartz.class).withIdentity("JobName""JobGroupName").build();    
  27.              
  28.                
  29.             // 定义调度触发规则    
  30.                            
  31.             // SimpleTrigger   
  32. //      Trigger trigger=TriggerBuilder.newTrigger().withIdentity("SimpleTrigger", "SimpleTriggerGroup")    
  33. //                    .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3).withRepeatCount(6))    
  34. //                    .startNow().build();    
  35.              
  36.             //  corn表达式  每五秒执行一次  
  37.               Trigger trigger=TriggerBuilder.newTrigger().withIdentity("CronTrigger1""CronTriggerGroup")    
  38.               .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))    
  39.               .startNow().build();     
  40.                
  41.             // 把作业和触发器注册到任务调度中    
  42.            scheduler.scheduleJob(job, trigger);    
  43.                
  44.            // 启动调度    
  45.            scheduler.start();    
  46.              
  47.            Thread.sleep(10000);  
  48.              
  49.            // 停止调度  
  50.            scheduler.shutdown();  
  51.                
  52.        }catch(SchedulerException e){    
  53.            e.printStackTrace();    
  54.        }    
  55.            
  56.    }    
  57. }    

 

 

输出(设置了sleep10秒, 故在0秒调度一次, 5秒一次, 10秒最后一次):

 

 

在trigger的选择上,一下可作为参考

1.SimpleTrigger 一般用于实现每隔一定时间执行任务,以及重复多少次,如每 60 秒执行一次,重复执行 6 次。

问题: (1) 在使用过程中发现设置执行6次其实是执行7次, 有一次是在开始执行的第 0 秒执行了一次, 然后根据执行间隔再执行给定的执行次数。

           (2) 当有 misfired 的任务并且恢复执行时,该执行时间是随机的(取决于何时执行 misfired 的任务,例如某天的 6:00PM)。这会导致之后每天的执行时间都会变成 6:00PM,而不是我们原来期望的时间。(PS: 因为这个问题, 我考虑不对外提供SimpleTrigger, 而换用DailyTimeIntervalTrigger)

 

 

2. CronTirgger 使用类似于 Linux/Unix 上的任务调度命令 crontab,具体参见Quartz入门详解的Cron表达式。对于涉及到星期和月份的调度,CronTirgger 是最适合的,甚至某些情况下是唯一选择。例如,"00 06 06 ? * WED 2014" 表示2014年每月每个星期三的 06:06AM 执行任务。

 

 

3. DailyTimeIntervalTrigger 会在给定的时间区间内每隔 N(1, 2, 3...)秒或小时执行任务。例如:设置从周一到周五10:10 ~ 18:00每60分钟执行一次。虽然 SimpleTrigger 也能实现类似的任务,但是DailyTimeIntervalTrigger 不会受到上面提到的 misfired 任务的问题。

 

 

4.CalendarIntervalTrigger 一般用于处理基于日历时间重复间隔任务。可以处理SimpleTrigger不能处理的任务(如:每个月的间隔秒数不同)和CronTrigger不能处理的任务(如:每5个月不是12的除数)。

 

 

除了上面提到的 4 种 Trigger,Quartz 中还定义了一个 Calendar 类(org.quartz.Calendar)。 Calendar 类与 Trigger 一起使用,它是用于排除任务不被执行的情况。例如,按照 Trigger 的规则在 5 月 1 号需要执行任务,但是 HolidayCalendar 指定了 5 月 1 号是法定假节日,所以任务在这一天将不会被执行。当然Calendar类不仅仅提供了节假日的排除, 还有Cron表达式排除等子类实现。

 

 

 

 

 

分享到:
评论

相关推荐

    quartz实例,quartz入门例子

    在这个Quartz入门例子中,可能包含了一个名为`QuarzTest`的类或配置文件,它是实际运行的入口。通过分析和运行这个例子,你可以了解到如何在Spring中配置和使用Quartz,以及如何创建和调度Job。 学习Quartz时,你...

    quartz入门到精通

    ### Quartz入门到精通知识点详解 #### 一、Quartz简介与特点 Quartz是一个功能强大的开源作业调度框架,主要用于Java应用程序中。它不仅易于使用,还提供了高度的灵活性,适用于各种复杂的调度需求。Quartz支持...

    Quartz入门学习(真丶入门)

    二、Quartz入门 1. **创建作业**:首先,你需要创建一个实现了`org.quartz.Job`接口的类,这个类就是你的任务逻辑。在`execute()`方法中编写实际的业务代码。 2. **定义触发器**:接着,定义一个触发器,设置执行...

    quartz入门共3页.pdf.zip

    通过阅读 "quartz入门共3页.pdf",你将能够快速了解 Quartz 的基本概念和用法,为实际项目开发打下基础。文件可能涵盖了 Quartz 的安装、基本示例、API 使用方法等内容,帮助你快速上手并掌握这个强大的任务调度库。

    Quartz入门教程

    "Quartz入门.html"这个文档可能详细介绍了如何设置和启动一个简单的Quartz调度程序。通常,你需要创建一个Job类,该类实现了`org.quartz.Job`接口,并重写了`execute`方法,这是实际执行的任务逻辑。然后,你可以...

    Quartz入门案例

    在"Quartz入门案例"中,我们通常会首先创建一个Job类,该类实现了`org.quartz.Job`接口。这个接口只有一个方法`execute(JobExecutionContext context)`,我们在其中编写实际的任务逻辑。例如: ```java public ...

    quartz入门demo

    【标题】"Quartz入门Demo"是一个非常适合初学者的实践项目,它旨在引导开发者了解和掌握Quartz这个强大的任务调度框架。Quartz是Java平台上广泛使用的开源任务调度库,能够帮助开发者实现应用程序中的定时任务执行。...

    Quartz入门到精通 中文WORD版.rar

    Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群...

    quartz入门例子,spring集成配置使用

    Spring集成quartz跑定时任务实例 自己写的例子并为实现job 有测试的主函数,请参考...springCon.quartz文件夹下 为对上诉博客理解透彻 结合spring看其配置的相关信息 就可以明白。

    Quartz如何从入门到精通.pdf

    Quartz入门到精通 Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如...

    开源定时器quartz入门

    NULL 博文链接:https://aiien007.iteye.com/blog/2105833

    quartz入门用法

    简单介绍quartz用法,介绍quartz用法步骤

    quartz案例,包括spring配置设置调度器和入门手册

    3. **Quartz入门** - **创建Job类**:你需要创建一个实现了`org.quartz.Job`接口的类,这个类定义了具体要执行的任务。 - **定义Trigger**:你可以选择不同的`Trigger`类型,如SimpleTrigger或CronTrigger,来决定...

    Quartz所需jar包

    在《Quartz入门》文档中,通常会详细讲解如何配置Quartz,包括XML配置、代码配置,以及如何处理并发问题、异常处理和集群部署。确保阅读并理解这些内容,以便更好地在实际项目中应用Quartz。 总之,Quartz是一个...

    Srping Quartz 资料多多

    "Quartz入门与提高1.ppt"可能是一个幻灯片教程,涵盖了从基础到进阶的Quartz使用。"定时任务Test.rar"可能包含了一些测试用例或示例代码,有助于理解实际应用场景。"网站地址.txt"可能提供了更多资源链接,而"quartz...

Global site tag (gtag.js) - Google Analytics