Quartz入门指南

看到官网的教程对于新手来说不够全面和连贯,因此结合自己的使用过程写下这个入门指南,用以解惑。本文基于Quartz2.2.2版本。请注意,本文为了易于上手,省略了许多重要的概念,建议阅读Quartz2.2.x官方教程

一、安装与配置

下载、解压后,进入lib文件夹,将所有jar文件放入项目指定目录,然后在BuildPath中添加。Jar包共6个,如下所示。

Quartz的运行依赖于log4j.xml和quartz.properties这两个配置文件。关于它们的配置方法,请查阅各自官网。我们偷个懒,就用下载包中的吧。在”quartz-2.2.2-distribution\quartz-2.2.2\examples\example11”目录下找到这俩文件,拷贝到项目指定位置,我是专门新建了个Config文件夹。然后在Eclipse中右击该目录,选择”Build Path -> Use as Source Folder”,即可。

二、Quartz框架

2.1 基本概念

Quartz中最核心的组件是任务、触发器和调度器。任务就是你指定的完成指定业务的执行单元。触发器规定了任务的执行时间、重复周期和频率。调度器将任务和触发器连接起来,它实际上管理着一个线程池和所有的任务和触发器,并进行统一的调度。

2.2 触发器

Quartz包含4种触发器,其中SimpleTrigger 和CronTrigger可能是最常用的,官方文档中对它们进行了详细的解释(请查看Quartz2.2.x官方教程,这里不再详述)。另外两种虽然只在javadoc中有只言片语的介绍,但在特定场景下仍具有不可替代性。

SimpleTrigger :在指定时间激活,然后以指定周期重复指定的次数。比如,14:30分开始,每隔10秒激活一次,重复100次。

CronTrigger:通过一个cron表达式来指定任务激活的年月日星期时分秒,以及重复周期。cron表达式具有一定的语法结构,可以达成非常强大的效果。不受夏令时引起的时钟偏移影响。

CalendarIntervalTrigger 根据一个给定的日历时间进行重复,可以设置启动时间。它可以完成 SimpleTrigger(比如每个月,因为月不是一个确定的秒数)和CronTrigger(比如5个月,因为5个月并不是12个月的公约数)不能完成的一些任务。注意,使用month作为周期单位时,如果起始日期是在某月的最后一天,比如1月31日,那么下一个激活日在2月28日,以后所有的激活日都在当月的28日。如果你要严格限制在每月的最后一天激活,那你需要使用cronTrigger。不受夏令时引起的时钟偏移影响。

DailyTimeIntervalTrigger:在给定的时间窗口或指定的星期以秒、分钟、小时为周期进行重复。比如,每天早上8:00到11:00之间,每隔72分钟激活;或者每周的周一到周五9:20到16:47之间,每隔23分钟激活。注意它的名称Daily,因此重复周期必须在1天以内,不能为星期,月之类的。

2.3 构造器

Quartz提供了构造器风格的API用于构造调度相关的实体。从官方给出的示例代码可以看出,各种实体都是使用构造器来生成的。Quartz中的构造器主要有以下几种:

TriggerBuilder:实例化触发器。

JobBuilder:构造JobDetail。

ScheduleBuilder:构造调度器,前面介绍的4种触发器分别有一个对应的调度器构造器。

DateBuilder:构造一个日期。

2.3.1 TriggerBuilder

通过其成员函数,能够定义触发器的开始、停止时间、job的各种属性及ScheduleBuilder。

具有4个子类,分别是SimpleScheduleBuilder,CronScheduleBuilder,CalendarIntervalScheduleBuilder,DailyTimeIntervalScheduleBuilder,对应4种触发器。在每个子类中,其成员函数均对其特有属性进行配置。比如说,SimpleScheduleBuilder具有repeatForever(),repeatHourlyForTotalCount(int count, int hours) 等方法来设置其重复周期和次数。其余方法不再具体介绍,请查阅javadoc。

2.3.2 JobBuilder

用于构造JobDetail,可想而知,它的成员方法均用于设置JobDetail的各种属性,比如description,dataMap,identity等等。

2.3.3 ScheduleBuilder

具有4个子类,分别为CalendarIntervalScheduleBuilder, CronScheduleBuilder, DailyTimeIntervalScheduleBuilder, SimpleScheduleBuilder,对应4个触发器,分别用于构造具体的某一种触发器。比如说,构造SimpleTrigger时,需要调用SimpleScheduleBuilder的simpleSchedule() 和build()方法;,构造CronTrigger时,需要调用CronScheduleBuilder的cronSchedule(String cronExpression) 和build()方法。其中,build()是由父类继承的,用于生成触发器。

2.3.4 DateBuilder

用于根据各种条件来构造一个日期。比如,dateOf(int hour,int minute, int second, int dayOfMonth, int month, int year),atHourOfDay(int atHour),evenHourDate(Date date),nextGivenMinuteDate(Date date, int minuteBase) ,tomorrowAt(int hour, int minute, int second),validateDayOfMonth(int day) 等等。

三、示例代码

使用SimpleTrigger的代码如下所示:

public void SimpleTriggerTest() throws Exception {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job1 = newJob(SimpleJob.class).withIdentity("job1", "group1")
.build();
Trigger trigger1 = newTrigger()//TriggerBuilder.newTrigger()
.startAt(DateBuilder.dateOf(10, 10, 10, 13, 3, 2016))
.withSchedule(
simpleSchedule().repeatSecondlyForTotalCount(5, 2))//<SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> schedBuilder)
.build();
Date ft = sched.scheduleJob(job1, trigger1);
sched.start();
}

有几个地方需要说明:

1.TriggerBuilder.newTrigger()。这是构造器,由于在头文件中已经使用了”import static org.quartz.TriggerBuilder.newTrigger;”静态引用所以不需要体现类名TriggerBuilder。startAt是它的方法,可以指定触发器的开始时间。

2.withSchedule方法的参数是一个schedBuilder,返回一个TriggerBuilder。

3.repeatSecondlyForTotalCount方法用于设置重复周期和次数,它是由simpleSchedule这个构造器提供的,而不是最终生成的simpleTrigger提供的,simpleTrigger没有相应方法。

完整的示例代码如下:

QuartzDemo.java

import static org.quartz.CalendarIntervalScheduleBuilder.calendarIntervalSchedule;
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger; import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.quartz.DateBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.TimeOfDay;
import org.quartz.Trigger;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.impl.StdSchedulerFactory; public class QuartzDemo { public void CalendarIntervalTriggerTest() throws SchedulerException{
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job = newJob(SimpleJob.class).withIdentity("job", "group1").build();
//每隔5个月,在指定日期和时间激活任务
Trigger trigger = newTrigger().startAt(DateBuilder.dateOf(10, 10, 10, 13, 3, 2016)).withSchedule(calendarIntervalSchedule().withInterval(5, IntervalUnit.MONTH)).build();
Date ft = sched.scheduleJob(job, trigger);
sched.start();
} public void CronTriggerTest() throws SchedulerException{
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job = newJob(SimpleJob.class).withIdentity("job2", "group1").build();
//每个周一到周五,早上8点-11点的整点激活任务,从明天早上9点开始
Trigger trigger = newTrigger().startAt(DateBuilder.tomorrowAt(9, 0, 0)).withIdentity("trigger2", "group1").withSchedule(cronSchedule("* 0 8-11 ? * MON-FRI"))
.build();
Date ft = sched.scheduleJob(job, trigger);
sched.start();
} public void DailyTimeIntervalTriggerTest() throws SchedulerException{
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job = newJob(SimpleJob.class).withIdentity("job2", "group1").build();
Set<Integer> daysOfWeek = new HashSet<Integer>();
daysOfWeek.add(Calendar.SATURDAY);
daysOfWeek.add(Calendar.SUNDAY);
//每个周末,20点-20点30分,每隔1分钟激活1次
Trigger trigger = newTrigger().startNow().withSchedule(dailyTimeIntervalSchedule().onDaysOfTheWeek(daysOfWeek).withInterval(1, IntervalUnit.MINUTE).withRepeatCount(5).startingDailyAt(new TimeOfDay(20,00)).endingDailyAt(new TimeOfDay(20,30)))
.build();
Date ft2 = sched.scheduleJob(job, trigger);
sched.start();
} public void SimpleTriggerTest() throws Exception {
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail job = newJob(SimpleJob.class).withIdentity("job1", "group1")
.build();
//在指定时间,按照指定周期和次数重复激活
Trigger trigger = newTrigger()//TriggerBuilder.newTrigger()
.startAt(DateBuilder.dateOf(10, 10, 10, 13, 3, 2016))
.withSchedule(
simpleSchedule().repeatSecondlyForTotalCount(5, 2))//<SBT extends T> TriggerBuilder<SBT> withSchedule(ScheduleBuilder<SBT> schedBuilder)
.build();
Date ft = sched.scheduleJob(job, trigger);
sched.start();
} public static void main(String[] args) throws Exception {
QuartzDemo example = new QuartzDemo();
//example.SimpleTriggerTest();
//example.DailyTimeIntervalTriggerTest();
//example.CalendarIntervalTriggerTest();
example.CronTriggerTest();
}
}

SimpleJob.java

import java.util.Date;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException; public class SimpleJob implements Job{
public SimpleJob() {
} public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.printf("SimpleJob executed at %s%n", new Date());
}
}

四、触发器选用实例

到这里,你应该对各种触发器的功能和参数设置方法有了一定的了解,但是仍然建议你看完以下实例,因为有一些你可能没有想到的问题。

4.1 每隔10秒

使用SimpleTrigger 就好。

4.2 每隔90分钟

使用SimpleTrigger或CalendarIntervalTrigger都可以。

4.3 每隔1天

使用CalendarIntervalTrigger 或CronTrigger。不建议使用SimpleTrigger ,因为夏令时的存在可能会使今天14点的24小时以后是明天的13点或者15点。

4.4 每隔2天

使用CalendarIntervalTrigger。不建议使用SimpleTrigger,原因如上。也不建议使用CronTrigger。试想一下,你的CronExpress的“日”这一位可能会写成“2/2”这样,表示每月的2号开始,每个2天。那么在7月的30号激活后,下一次激活是在8月的2号,这个间隔就是3天而不是2天(7月有31天)。

4.5 每隔1周

使用CronTrigger或者CalendarIntervalTrigger都可以。

4.6 每隔2周

与“2天”同样的原因,使用CronTrigger会有问题,因此建议使用CalendarIntervalTrigger。

4.7 每隔1个月

使用CronTrigger或CalendarIntervalTrigger。

4.8 每隔5个月

使用CalendarIntervalTrigger。与“2天”同样的原因,使用CronTrigger会有问题。试想一下,你的CronExpress的“月”这一位可能会写成“3/5”这样,那么8月激活后,下一个激活点在第二年3月,这个间隔就成了7个月。

五、参考资料

Quartz Scheduler Example Programs and Sample Code

Quartz Enterprise Job Scheduler 2.2.1 API

Quartz入门指南的更多相关文章

  1. Quartz.NET快速入门指南

    最近,在工作中遇到了 Quartz.net 这个组件,为了更好的理解项目代码的来龙去脉,于是决定好好的研究一下这个东西.确实是好东西,既然是好东西,我就拿出来分享一下.万丈高楼平地起,我们也从入门开始 ...

  2. Quartz.NET简介及入门指南

    Quartz.NET简介 Quartz.NET是一个功能完备的开源调度系统,从最小的应用到大规模的企业系统皆可适用. Quartz.NET是一个纯净的用C#语言编写的.NET类库,是对非常流行的JAV ...

  3. 张高兴的 .NET IoT 入门指南:(七)制作一个气象站

    距离上一篇<张高兴的 .NET Core IoT 入门指南>系列博客的发布已经过去 2 年的时间了,2 年的时间 .NET 版本发生了巨大的变化,.NET Core 也已不复存在,因此本系 ...

  4. Web API 入门指南 - 闲话安全

    Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...

  5. Vue.js 入门指南之“前传”(含sublime text 3 配置)

    题记:关注Vue.js 很久了,但就是没有动手写过一行代码,今天准备入手,却发现自己比菜鸟还菜,于是四方寻找大牛指点,才终于找到了入门的“入门”,就算是“入门指南”的“前传”吧.此文献给跟我一样“白痴 ...

  6. yii2实战教程之新手入门指南-简单博客管理系统

    作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...

  7. 【翻译】Fluent NHibernate介绍和入门指南

    英文原文地址:https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started 翻译原文地址:http://www.cnblogs ...

  8. ASP.NET MVC 5 入门指南汇总

    经过前一段时间的翻译和编辑,我们陆续发出12篇ASP.NET MVC 5的入门文章.其中大部分翻译自ASP.NET MVC 5 官方教程,由于本系列文章言简意赅,篇幅适中,从一个web网站示例开始讲解 ...

  9. 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍

    我们在前一篇文章微软新神器-Power BI,一个简单易用,还用得起的BI产品中,我们初步介绍了Power BI的基本知识.由于Power BI是去年开始微软新发布的一个产品,虽然已经可以企业级应用, ...

随机推荐

  1. Python垃圾回收机制 总结

    Python 垃圾回收机制 内存管理 Python中的内存管理机制的层次结构提供了4层,其中最底层则是C运行的malloc和free接口,往上的三层才是由Python实现并且维护的,第一层则是在第0层 ...

  2. 记一次小型生产事故 | BeyondComper跨编码方式复制文件内容

    前言 今天组长在做站内巡检的时候,发现header内有一条meta标签的content显示为乱码. <meta name="description" content=&quo ...

  3. FTP服务

    FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为 "文传协议" 用于Internet上的控制文件的双向传输.同时,它也是一个应用程序( ...

  4. PYTHON:新闻聚合

    这个项目看了有段时间,因为一直没跑通,而且关于NNTP也不是特别理解.这里是转载code123的分析. 原文地址:http://www.code123.cc/1327.html 书中的第四个练习,新闻 ...

  5. servlet实现登陆注册

    拿到信息必须进行非空验证用servlet做注册登陆时,在form表单的action中不用加后缀.java,jsp文件需要加 public boolean CheckParm(String...args ...

  6. [js高手之路]从原型链开始图解继承到组合继承的产生

    基于javascript原型链的层层递进查找规则,以及原型对象(prototype)的共享特性,实现继承是非常简单的事情 一.把父类的实例对象赋给子类的原型对象(prototype),可以实现继承 f ...

  7. 【Centos】yum安装MySQL

    安装步骤 1. 点击此处下载MySQL的YUM源 -- [ MySQL RPM] 选择适合你平台的rpm,我的是centos7 2. 安装MySQL的yum源,即RPM sudo yum locali ...

  8. JavaScript对象遍历

    一.对象是数组: var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1]; //each遍历: $.each(arr,function (index,value) { alert( ...

  9. web中转发、重定向等问题的路径

    web中常用路径,转发,重定向,form表单action的路径 路径的写法: a.绝对路径写法:ServeltContext都必须用绝对路径."/" b.相对路径:其他情况都可以使 ...

  10. hdu3081 Marriage Match II(二分+并查集+最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3081 题意: n个女生与n个男生配对,每个女生只能配对某些男生,有些女生相互是朋友,每个女生也可以跟她 ...