在软件开发中经常会遇到使用任务调度的情况,比如需要定时,或者某个时刻执行某项任务。Quartz 是一个在java开中优秀的可选框架。
Quartz 是一个Java下作业控制的开源框架。用来创建或简单或复杂的调度时间表,执行Java下任意数量的作业。
示例用途:
特征
在官网下载 jar 包 http://www.quartz-scheduler.org/downloads/ 或者使用 maven 集成:
(1) 添加依赖 依赖核心库和 logback 的日志。
<!-- Quartz 核心库 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<!-- Quartz 使用了 SLF4J, 这里指定了一个实际使用的 logger -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
(2) 添加一个配置文件 在resources 文件下新建一个 quartz.properties 配置文件,这个配置文件不是必须的,不过仍然建议将配置内容放入到一个配置文件中,这样的配置文件比写在代码里更方便修改。
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 5
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
(3) 编写一个 Job ,即作业类 一个 quertz 作业必须是实现了 Job 接口的实现类,实现 execute 方法,在 execute 方法的参数中可以获得一个 JobExecutionContext 上下文对象。 示例如下:
public static class MyJob implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
System.out.println("Run ..." + now);
}
}
(4)开始执行作业 分几个初始化的步骤:
说明:
示例代码:
public static void main(String[] args) throws InterruptedException {
try {
// 装载一个 调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
// 创建一个 job 作业
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("job1", "group1")
.build();
// 创建触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("triger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder // 创建执行日程,这里是间隔4秒且始终循环
.simpleSchedule()
.withIntervalInSeconds(4)
.repeatForever())
.build();
// 将 作业 加入到调度器中
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
// 为了让程序不终止
Thread.sleep(60000);
}
Quartz API 的关键接口是:
Scheduler
调度器 - 调度程序的主要对象。Job
作业 - 业务逻辑要实现的接口,你要执行的任务。JobDetail
作业实例 - 用于定义作业的实例。它使用 JobBuilder 来创建 JobDetail 实例Trigger
触发器 - 它定义了在某个时刻触发作业的方式。它使用 TriggerBuilder 构建 Trigger 实例。主要示例:
// define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.build();
// Trigger the job to run now, and then every 40 seconds
Trigger trigger = newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build();
// Tell quartz to schedule the job using our trigger
sched.scheduleJob(job, trigger);
Quartz 附带了一些不同的触发器类型,最常用的是
如果您需要在给定的时间只执行一次作业,或者需要在给定的时间触发作业,并让它重复 N 次,可选择 SimpleTrigger。
如果您希望基于类似日历的时间表进行触发,例如“每个星期五中午”或“每个月的第 10 天的 10:15”,可选择 CronTrigger 。
在使用 调度器(Scheduler),要先实例化一个 调度器,可使用 SchedulerFactory 来做。
要注意的是,调度器在实例化以后,要先启动调度器才能触发作业的执行,示例如下:
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
Scheduler sched = schedFact.getScheduler();
sched.start();
Quartz 的 Calendar 日历对象(注意不是 java.util.Calendar 对象)可以在触发器中被定义,它存在在调度程序中通过名称与触发器关联。
日历在从触发器中排除 某个时间段 很有用。例如,创建每个工作日的上午 9:30 触发的工作,然后排除所有法定假期日历。
为方便起见,Quartz 包含了 org.quartz.impl.HolidayCalendar 类。
日历示例
HolidayCalendar cal = new HolidayCalendar();
cal.addExcludedDate( someDate );
cal.addExcludedDate( someOtherDate );
sched.addCalendar("myHolidays", cal, false);
Trigger t = newTrigger()
.withIdentity("myTrigger")
.forJob("myJob")
.withSchedule(dailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
.modifiedByCalendar("myHolidays") // but not on holidays
.build();
// .. schedule job with trigger
Trigger t2 = newTrigger()
.withIdentity("myTrigger2")
.forJob("myJob2")
.withSchedule(dailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
.modifiedByCalendar("myHolidays") // but not on holidays
.build();
如果您需要在特定时刻执行一次作业,或者在特定时刻执行一次,然后以特定间隔重复执行,可选择 SimpleTrigger。
SimpleTrigger 的属性包括:
更多请阅读:https://github.com/quartz-scheduler/quartz/blob/master/docs/tutorials/tutorial-lesson-05.md
使用 CronTrigger,您可以指定触发时间表,例如“每个星期五中午”或“每个工作日和上午 9:30”,甚至“每个星期一、星期三上午 9:00 到上午 10:00 之间每 5 分钟一次”和一月份的星期五”。
Cron 表达式 Cron-Expressions用于配置 CronTrigger 的实例。Cron-Expressions 是实际上由七个子表达式组成的字符串,它们描述了计划的各个细节。这些子表达式用空格分隔,表示:
示例 Cron 表达式 CronTrigger 示例 1 - 创建触发器的表达式,该触发器每 5 分钟触发一次
“0 0/5 * * * ?”
CronTrigger 示例 2 - 创建触发器的表达式,该触发器每 5 分钟触发一次,每分钟后 10 秒(即上午 10:00:10、上午 10:05:10 等)。
“10 0/5 * * * ?”
CronTrigger 示例 3 - 创建触发器的表达式,该触发器在每周三和周五的 10:30、11:30、12:30 和 13:30 触发。
“0 30 10-13 ?*周三,周五”
构建一个触发器,它会在每天早上 8 点到下午 5 点之间每隔一分钟触发一次:
构建 CronTriggers 的示例
trigger = newTrigger()
.withIdentity("trigger3", "group1")
.withSchedule(cronSchedule("0 0/2 8-17 * * ?"))
.forJob("myJob", "group1")
.build();
侦听器是您创建的对象,用于根据调度程序中发生的事件执行操作。
大多数情况不使用侦听器,但在需要事件通知
时很方便。
触发器监听器( TriggerListeners) TriggerListeners接收与触发器相关的事件
作业监听器(JobListeners) JobListeners 接收与作业相关的事件。
调度程序监听器(SchedulerListeners) 用于接收 Scheduler 本身内的事件通知。
内存存储库(RAMJobStore) RAMJobStore 是使用最简单的 JobStore,它也是性能最高的。RAMJobStore 以显而易见的方式得名:它将所有数据保存在 RAM 中。缺点是当您的应用程序结束(或崩溃)时,所有调度信息都将丢失。
配置 Quartz 以使用 RAMJobStore:
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
JDBC作业存储 (JDBCJobStore) 它通过 JDBC 将所有数据保存在数据库中,检索和更新触发触发器的时间通常少于 10 毫秒。
要使用 JDBCJobStore,您必须首先创建一组数据库表,docs/dbTables”目录中找到创建表的 SQL 脚本,需要注意的一件事是,在这些脚本中,所有表都以前缀“QRTZ_”开头。
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix = QRTZ_
如果您的调度程序很忙, 几乎总是执行与线程池大小相同数量的作业,那么您应该将 DataSource 中的连接数设置为线程池大小 + 2。
集群 集群目前适用于 JDBC-Jobstore(JobStoreTX 或 JobStoreCMT)和 TerracottaJobStore。功能包括负载平衡和作业故障转移(如果 JobDetail 的“请求恢复”标志设置为 true)。
使用 JobStoreTX 或 JobStoreCMT 进行聚类 通过将“org.quartz.jobStore.isClustered”属性设置为“true”来启用集群。
集群中的每个实例都应该使用quartz.properties 文件的相同副本。
例外情况是使用相同的属性文件,集群中的每个节点必须有一个唯一的 instanceId,通过将“AUTO”作为该属性的值可以完成(不需要不同的属性文件)。
官方网址: http://www.quartz-scheduler.org/ Github: https://github.com/quartz-scheduler/quartz/tree/master/docs/tutorials 官方训练课程 https://github.com/quartz-scheduler/quartz/tree/master/docs/tutorials