建议从Getting started with Quartz开始,先写一个非常简单的demo,基于这个demo,去理解后面的内容。
Using Quartz
在使用调度器之前,应当先实例化一个,这便用到了SchedulerFactory
。也有人将factory
的一个实例保存在了JDNI(Java Naming and Directory Interface)存储,因此实例化一个调度器也就更容易了。
调度器一旦被实例化完成,它可以被启动,可以处于等待模式,也可以被关闭。注意,一旦一个调度器关闭了,如果不重新实例化,它就不能重新启动。如果调度器并未被启动,或者整出一暂停状态,触发器也不会被触发(作业并不会执行)。
以下代码片段实例化并启动了一个调度器,并调度执行了一个作业
123456789101112131415161718192021222324 | SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();Scheduler sched = schedFact.getScheduler();sched.start();JobDetail job = JobBuilder.newJob(HelloJob.class) .withIdentity("myJob", "group1") .build();// Trigger the job to run now, and then every 40 secondsTrigger trigger = TriggerBuilder .newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(SimpleScheduleBuilder .simpleSchedule() .withIntervalInSeconds(40) .repeatForever()) .build();// Tell quartz to schedule the job using our triggersched.scheduleJob(job, trigger); |
如上所示,用Quartz干活就是这么简单。
The Quartz API, Jobs and Trigger
The Quartz API
Quratz API 的核心接口如下
Scheduler
- 和调度器进行交互的核心APIJob
- 你需要去实现的接口,里面放着你想让调度器执行的JobDetail
- 用于定义Job
的实例Trigger
- 一个用于告知调度器去执行哪个作业的组件JobBuilder
- 用于定义/构建JobDetail
的实例TriggerBuilder
- 用于定义/构建Trigger
的实例
一个调度器(Scheduler
)的生命周期以SchedulerFactory
对它的创建为起始,到调用它的shutdown()
为终止。创建了调度器实例后,就能添加、移除或者列出触发器及作业,或者执行其它调度相关的操作(例如暂停一个触发器)。但是,在调度器启动起来之前,它不会对任何触发器或作业执行任何实际操作。
Quartz提供了一系列定义了领域专用语言(DSL)的builder
类,上一节已经见到过了,此处我们再贴出来
12345678910111213141516 | JobDetail job = newJob(HelloJob.class) .withIdentity("myJob", "group1") // name "myJob", group "group1" .build();// Trigger the job to run now, and then every 40 secondsTrigger trigger = newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(40) .repeatForever()) .build();// Tell quartz to schedule the job using our triggersched.scheduleJob(job, trigger); |
构建一个Job
使用的方法是我们从JobBuilder
类中静态导入的;同样的,构建一个触发器的方法也是从TriggerBuilder
类中静态导入的,也有来自SimpleScheduleBuilder
类中的。
DSL的静态导入可以通过以下这些import
语句做到:
123456 | import static org.quartz.JobBuilder.*;import static org.quartz.SimpleScheduleBuilder.*;import static org.quartz.CronScheduleBuilder.*;import static org.quartz.CalendarIntervalScheduleBuilder.*;import static org.quartz.TriggerBuilder.*;import static org.quartz.DateBuilder.*; |
这些ScheduleBuilder
类有创建不同类型调度器的方法。其中DateBuilder
类包含的一系列方法,能很容易创建各种“奇怪”时间点的java.util.Date
的实例。
Jobs and Triggers
一个作业(Job)指的是一个实现了Job
接口的类,该接口只有一个简单的方法
1234567 | package org.quartz;// the Job interfacepublic interface { public void execute(JobExecutionContext context) throws JobExecutionException;} |
当该作业的触发器被触发,它的execute
方法就会被调度器的一个工作线程激活。传给这个方法的JobExecutionContext
对象给这个作业对象传递了它“运行时刻”的环境信息-调度执行它的调度器的句柄,被触发从而引发该方法执行的那个个触发器的句柄,这个作业的JobDetail
对象,还有一些其它的东西。
当作业被加入到调度器的时候,Quartz客户端(就是你的程序)就创建了一个JobDetail
对象。它包含了各种用于设置这个作业的属性,包括一个JobDataMap
,它可用于保存给定的作业类实例的状态信息。它是作业实例的本质定义,我们将会在下一节讨论它。
Trigger
对象用于触发作业的执行。当你希望调度一个作业时,实例化一个触发器然后调整它的属性,使之调度安排符合预期。触发器也有与之关联的JobDataMap
-当需要给作业传递特定参数的时候,它就非常有用了。Quartz提供了多种类型的触发器,但大家大多使用SimpleTrigger
和CronTrigger
。
当你需要“单触发”的运行(就是在某个给定时刻,某个作业只有单个的执行),或者你需要在给定的时刻触发作业,重复多次,在多次执行之间需要延迟,SimpleTrigger
是非常好用的。如果你需要“类日历式”调度作业,例如“每周五下午”或者“每月10日的上午10:15”,CronTrigger
是非常好用的。
为何Job
和Trigger
要组合存在呢?很多调度器并不刻意区分作业和触发器的概念。有些定义一个作业只是简单定义了一个执行时间(或调度)和一些小的作业标识符,有的就比较像是组合了Quartz的作业和触发器对象。开发Quartz的时候,我们决定分离调度和调度要执行的作业,是因为(我们认为)这有很多益处。
例如,作业可以被创建然后存储在调度器中,它跟触发器互相独立,多个触发器可以关联一个作业。另一个解耦的优势在于,当与某个作业关联的触发器被销毁之后,调度器依然能持有这个作业,使之能被重新调度,而不需要在定义一个该作业。这种做法也允许你修改或者替换触发器,而不用重新定义它关联的作业。
Identities
作业和触发器在被注册到Quartz调度器时,都给定了一个特征码。作业和调度器的特征码的存在,允许它们可以被放置在“group”中,这样就能更方便地管理作业和触发器了。在组内部,触发器或作业地名称必须是唯一的,作业或触发器的特征码是自身名和组名组合起来的。
原文:大专栏 Quartz Tutorial 1 - Using Quartz & The Quartz API, Jobs and Trigger