Quartz入门指南
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入门指南的更多相关文章
- Quartz.NET快速入门指南
最近,在工作中遇到了 Quartz.net 这个组件,为了更好的理解项目代码的来龙去脉,于是决定好好的研究一下这个东西.确实是好东西,既然是好东西,我就拿出来分享一下.万丈高楼平地起,我们也从入门开始 ...
- Quartz.NET简介及入门指南
Quartz.NET简介 Quartz.NET是一个功能完备的开源调度系统,从最小的应用到大规模的企业系统皆可适用. Quartz.NET是一个纯净的用C#语言编写的.NET类库,是对非常流行的JAV ...
- 张高兴的 .NET IoT 入门指南:(七)制作一个气象站
距离上一篇<张高兴的 .NET Core IoT 入门指南>系列博客的发布已经过去 2 年的时间了,2 年的时间 .NET 版本发生了巨大的变化,.NET Core 也已不复存在,因此本系 ...
- Web API 入门指南 - 闲话安全
Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...
- Vue.js 入门指南之“前传”(含sublime text 3 配置)
题记:关注Vue.js 很久了,但就是没有动手写过一行代码,今天准备入手,却发现自己比菜鸟还菜,于是四方寻找大牛指点,才终于找到了入门的“入门”,就算是“入门指南”的“前传”吧.此文献给跟我一样“白痴 ...
- yii2实战教程之新手入门指南-简单博客管理系统
作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...
- 【翻译】Fluent NHibernate介绍和入门指南
英文原文地址:https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started 翻译原文地址:http://www.cnblogs ...
- ASP.NET MVC 5 入门指南汇总
经过前一段时间的翻译和编辑,我们陆续发出12篇ASP.NET MVC 5的入门文章.其中大部分翻译自ASP.NET MVC 5 官方教程,由于本系列文章言简意赅,篇幅适中,从一个web网站示例开始讲解 ...
- 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍
我们在前一篇文章微软新神器-Power BI,一个简单易用,还用得起的BI产品中,我们初步介绍了Power BI的基本知识.由于Power BI是去年开始微软新发布的一个产品,虽然已经可以企业级应用, ...
随机推荐
- UUID.randomUUID().toString() 的作用
public static String createNewId(){ return UUID.randomUUID().toString() ; } UUID.randomUUID().toStri ...
- springMVC修改用户请求内容
最近在做一个微信相关的网站,很多地方涉及到微信表情的输入,导致内容无法插入到数据库,虽然有用到一个表情过滤的工具类,但是需要过滤的地方比较多,于是想到在过滤器中过滤用户请求的内容. request这个 ...
- 扩展Python模块系列(二)----一个简单的例子
本节使用一个简单的例子引出Python C/C++ API的详细使用方法.针对的是CPython的解释器. 目标:创建一个Python内建模块test,提供一个功能函数distance, 计算空间中两 ...
- 移动端表层div滑动,导致底层body滑动(touchmove的阻止)
body很长,可以滑动,body头部有一个模拟下拉的选择框,下拉选择有滚动轴 我给body一个overflow:hidden和高度是没有用的.手机网站上背景还是可以滑动,然后我给body一个touch ...
- Swoole笔记(四)
Process Process是swoole内置的进程管理模块,用来替代PHP的pcntl扩展. swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读 ...
- Mac terminal commands
Mac terminal commands 1.install_name_tool修改dylib安装名称的命令 2.codesign 签名及查看 3.xcode 工程编译 4.程序打包app---&g ...
- 免费的Lucene 原理与代码分析完整版下载
Lucene是一个基于Java的高效的全文检索库.那么什么是全文检索,为什么需要全文检索?目前人们生活中出现的数据总的来说分为两类:结构化数据和非结构化数据.很容易理解,结构化数据是有固定格式和结构的 ...
- html js文字左右滚动插件
自己写过很多插件,但都是直接嵌入在了工程里,从来没有拿出来单独封装成一个文件过,这是第一次,希望是一个良好的开端. 一个文字过长而可以左右滚动的插件 <!DOCTYPE html> < ...
- ZOJ 3811 Untrusted Patrol The 2014 ACM-ICPC Asia Mudanjiang Regional First Round
Description Edward is a rich man. He owns a large factory for health drink production. As a matter o ...
- 史上最全前端面试题(含答案)-A篇
HTML+CSS1.对WEB标准以及W3C的理解与认识标签闭合.标签小写.不乱嵌套.提高搜索机器人搜索几率.使用外 链css和js脚本.结构行为表现的分离.文件下载与页面速度更快.内容能被更多的用户所 ...