一、简介
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,是完全由java开发的一个开源的任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。Quartz用一个小Java库发布文件(.jar文件),这个库文件包含了所有Quartz核心功能。这些功能的主要接口(API)是Scheduler接口。它提供了简单的操作,例如:将任务纳入日程或者从日程中取消,开始/停止/暂停日程进度。
二、quartz的核心类
分别是 Scheduler(调度器)Job(任务)和 Trigger (触发器),它们是我们使用 Quartz 的关键。
(1)、Job:定义需要执行的任务。该类需要实现Job接口,只定义一个方法 execute(JobExecutionContext context),在实现类的 execute 方法中编写所需要定时执行的 Job(任务), JobExecutionContext 类提供了调度应用的一些信息。Job 运行时的信息保存在 JobDataMap 实例中。
(2)、Trigger:负责设置调度策略。该类是一个接口,描述触发 job 执行的时间触发规则。主要有 SimpleTrigger 和 CronTrigger 这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;而 CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的 15:00~16:00 执行调度等。
(3)、Scheduler:调度器就相当于一个容器,装载着任务和触发器。该类是一个接口,代表一个 Quartz 的独立运行容器, Trigger 和 JobDetail 可以注册到 Scheduler 中, 两者在 Scheduler 中拥有各自的组及名称, 组及名称是 Scheduler 查找定位容器中某一对象的依据, Trigger 的组及名称必须唯一, JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法, 允许外部通过组及名称访问和控制容器中 Trigger 和 JobDetail。
(4)、JobDetail:描述 Job 的实现类及其它相关的静态信息,如:Job 名字、描述、关联监听器等信息。Quartz 每次调度 Job 时, 都重新创建一个 Job 实例, 所以它不直接接受一个 Job 的实例,相反它接收一个 Job 实现类,以便运行时通过 newInstance() 的反射机制实例化 Job。
(1)、Job:定义需要执行的任务。该类需要实现Job接口,只定义一个方法 execute(JobExecutionContext context),在实现类的 execute 方法中编写所需要定时执行的 Job(任务), JobExecutionContext 类提供了调度应用的一些信息。Job 运行时的信息保存在 JobDataMap 实例中。
(2)、Trigger:负责设置调度策略。该类是一个接口,描述触发 job 执行的时间触发规则。主要有 SimpleTrigger 和 CronTrigger 这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;而 CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的 15:00~16:00 执行调度等。
(3)、Scheduler:调度器就相当于一个容器,装载着任务和触发器。该类是一个接口,代表一个 Quartz 的独立运行容器, Trigger 和 JobDetail 可以注册到 Scheduler 中, 两者在 Scheduler 中拥有各自的组及名称, 组及名称是 Scheduler 查找定位容器中某一对象的依据, Trigger 的组及名称必须唯一, JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法, 允许外部通过组及名称访问和控制容器中 Trigger 和 JobDetail。
(4)、JobDetail:描述 Job 的实现类及其它相关的静态信息,如:Job 名字、描述、关联监听器等信息。Quartz 每次调度 Job 时, 都重新创建一个 Job 实例, 所以它不直接接受一个 Job 的实例,相反它接收一个 Job 实现类,以便运行时通过 newInstance() 的反射机制实例化 Job。
三、调度示例
main执行类:package quartz;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.DateBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
public class ScheduleMain {
public static void main(String[] args) throws SchedulerException {
//1、 通过 schedulerFactory 获取一个调度器
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler;
try {
scheduler = sf.getScheduler();
//2、 创建 jobDetail 实例,绑定 Job 实现类(指明 job 的名称,所在组的名称,以及绑定 job 类)
JobDetail job = JobBuilder.newJob(TimerJob.class).withIdentity("Job1","group1").build();
// 3、定义调度触发规则
// 3.1、SimpleTrigger,从当前时间的下 1 秒开始,每隔 1 秒执行 1 次,重复执行 2 次
// //Trigger trigger = (Trigger) TriggerBuilder.newTrigger()
// //.withIdentity("trigger4", "group1") / / 指明 trigger 的 name 和 group
// .startNow() //默认为立即开始执行
// .startAt(DateBuilder.evenSecondDate(new Date())) // 从当前时间的下 1 秒开始执行
// .withSchedule(SimpleScheduleBuilder.simpleSchedule()
// .withIntervalInSeconds(5) // 每隔 5秒执行 1 次
// .withRepeatCount(50)) // 重复执行 50次,一共执行 51 次
// .build();
// 3.2、CronTrigger ,先立即执行一次,然后每隔 1 秒执行 1 次
Trigger trigger = (Trigger) TriggerBuilder.newTrigger()
.withIdentity("trigger1","group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/1 * * * * ?"))//[秒] [分] [时] [每月的第几日] [月] [每周的第几日] [年]
.build();
// 4、初始化参数传递到 job(可根据需求决定)
job.getJobDataMap().put("Description", "day day up");
job.getJobDataMap().put("Value", 1998);
List<String> list = new ArrayList<>();
list.add("good good study");
job.getJobDataMap().put("Array", list);
// 5、把作业和触发器注册到任务调度中
scheduler.scheduleJob(job,trigger);
// 6、启动计划程序(实际上直到调度器已经启动才会开始运行)
scheduler.start();
// 7、关闭调度器
//scheduler.shutdown(true);
} catch (SchedulerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
Job任务类:
package quartz;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class TimerJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 从 context 中获取 instName, groupName 以及 dataMap
String jobName = context.getJobDetail().getKey().getName();
String groupName = context.getJobDetail().getKey().getGroup();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
// 从 dataMap 中获取 Description, Value 以及 Array
String description = dataMap.getString("Description");
int Value = dataMap.getInt("Value");
List<String> array = (List<String>)dataMap.get("Array");
//打印JobDetail和JobDataMap的信息
System.out.println("---> JobName = " + jobName + ", GroupName = " + groupName+", Description = "
+ description + ", Value =" + value+" , Array item[0] = " + array.get(0));
}
}
四、 cronExpression 表达式
4.1、格式:[秒] [分] [时] [每月的第几日] [月] [每周的第几日] [年]字段名 | 必须的 | 允许值 | 允许的特殊字符 |
---|---|---|---|
Seconds | YES | 0-59 | , - * / |
Minutes | YES | 0-59 | , - * / |
Hours | YES | 0-23 | , - * / |
Day of month | YES | 1-31 | , - * ? / L W |
Month | YES | 1-12 or JAN-DEC | , - * / |
Day of week | YES | 1-7 or SUN-SAT | , - * ? / L # |
Year | NO | empty, 1970-2099 | , - * / |
4.2、特殊字符说明
字符 | 含义 |
---|---|
* | 用于 指定字段中的所有值。比如:* 在分钟中表示 每一分钟。 |
? | 用于 指定日期中的某一天,或是 星期中的某一个星期。 |
- | 用于 指定范围。比如:10-12 在小时中表示 10 点,11 点,12 点。 |
, | 用于 指定额外的值。比如:MON,WED,FRI 在日期中表示 星期一, 星期三, 星期五。 |
/ | 用于 指定增量。比如:0/15 在秒中表示 0 秒, 15 秒, 30 秒, 45 秒。5/15 在秒中表示 5 秒,20 秒,35 秒,50 秒。 |
L | 在两个字段中拥有不同的含义。比如:L 在日期(Day of month)表示 某月的最后一天。在星期(Day of week)只表示 7 或 SAT。但是,值L 在星期(Day of week)中表示 某月的最后一个星期几。 比如:6L 表示 某月的最后一个星期五。也可以在日期(Day of month)中指定一个偏移量(从该月的最后一天开始).比如:L-3 表示 某月的倒数第三天。 |
W | 用于指定工作日(星期一到星期五)比如:15W 在日期中表示 到 15 号的最近一个工作日。如果第十五号是周六, 那么触发器的触发在 第十四号星期五。如果第十五号是星期日,触发器的触发在 第十六号周一。如果第十五是星期二,那么它就会工作开始在 第十五号周二。然而,如果指定 1W 并且第一号是星期六,那么触发器的触发在第三号周一,因为它不会 "jump" 过一个月的日子的边界。 |
L和W | 可以在日期(day-of-month)合使用,表示 月份的最后一个工作日。 |
# | 用于 指定月份中的第几天。比如:6#3 表示 月份的第三个星期五(day 6 = Friday and "#3" = the 3rd one in the month)。其它的有,2#1 表示 月份第一个星期一。4#5 表示 月份第五个星期三。注意: 如果只是指定 #5,则触发器在月份中不会触发。 |
4.3、 cronExpression 示例
表达式 | 含义 |
---|---|
0 0 12 * * ? | 每天中午 12 点 |
0 15 10 ? * * | 每天上午 10 点 15 分 |
0 15 10 * * ? | 每天上午 10 点 15 分 |
0 15 10 * * ? * | 每天上午 10 点 15 分 |
0 15 10 * * ? 2005 | 在 2005 年里的每天上午 10 点 15 分 |
0 * 14 * * ? | 每天下午 2 点到下午 2 点 59 分的每一分钟 |
0 0/5 14 * * ? | 每天下午 2 点到 2 点 55 分每隔 5 分钟 |
0 0/5 14,18 * * ? | 每天下午 2 点到 2 点 55 分, 下午 6 点到 6 点 55 分, 每隔 5 分钟 |
0 0-5 14 * * ? | 每天下午 2 点到 2 点 5 分的每一分钟 |
0 10,44 14 ? 3 WED | 3 月每周三的下午 2 点 10 分和下午 2 点 44 分 |
0 15 10 ? * MON-FRI | 每周一到周五的上午 10 点 15 分 |
0 15 10 15 * ? | 每月 15 号的上午 10 点 15 分 |
0 15 10 L * ? | 每月最后一天的上午 10 点 15 分 |
0 15 10 L-2 * ? | 每月最后两天的上午10点15分 |
0 15 10 ? * 6L | 每月的最后一个星期五的上午 10 点 15 分 |
0 15 10 ? * 6L 2002-2005 | 2002 年到 2005 年每个月的最后一个星期五的上午 10 点 15 分 |
0 15 10 ? * 6#3 | 每月的第三个星期五的上午 10 点 15 分 |
0 0 12 1/5 * ? | 每月的 1 号开始每隔 5 天的中午 12 点 |
0 11 11 11 11 ? | 每年 11 月 11 号上午 11 点 11 分 |
5、总结: 小强也是由于工作的需要刚刚接触quartz不久,在这只是将学习过程中的一些知识记了下来在这只是大概阐述了quartz的基本使用,并没有进行深入的了解quartz的难点部分。小强在学习中也是翻阅了很多的博客,总之学习之路是痛苦的重要的是能在痛苦中找到快乐。