1 Quartz 简介
Quartz 是基于Java 实现的一个开源的调度框架, 是开源组织OpenSymphony 的产品。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。官方网站:www.quartz-scheduler.org/ 。
本人在产品开发中使用的是版本 2.3.0,因此本文内容也基于该版本。
2 Quartz功能及特点
运行环境
Quartz 能通过JVM独立运行
Quartz 能在一个应用服务器里被实例化(或servlet容器), 并且可以作为XA事务的一部分来运行
Quartz 能被集群化部署运行, 也可以单机方式运行
任务调度
任务有多种调度方式, 非常灵活:
- 指定按某个时间间隔无限循环,例,每3分钟,每30秒
- 指定到一天的某个时间点(精确到毫秒级), 例,每天的01:00:00, 每天的17:25:30
- 指定只在一个固定时间点运行,例 2019-05-22 13:52:20
- 通过Calendar排除某些时间 (例如节假日)
- 循环重复的更灵活配置等等
任务执行
- 任务可以是任何实现Job接口的Java类。一个任务可以有多种调度方式,任务与调度之间是解耦的,可自由组合。
任务持久化
- 可以通过配置JobStoreCMT或JobStoreTX,可以实现任务的持久化。
- 通过配置RAMJobStore, 可以将任务和触发器存储在内存里,运行性能更高。
事务
- 使用JobStoreCMT(JDBCJobStore的子类),Quartz任务能作为JTA事务的一部分运行。
集群
开启集群模式部署运行后,系统具有集群的通用特性
- Fail-over
- Load balancing
监听器和插件
- 通过实现一个或多个监听接口,应用程序能捕捉调度事件来监控或控制任务/触发器的行为。
- 插件机制可以给Quartz增加功能,例如保持任务执行的历史记录,或从一个定义好的文件里加载任务和触发器。
- Quartz 在运行过程中,很多地方都会回调监听器和插件。
容易与Spring集成
作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成
3 核心元素
Quartz 核心元素之间的关系如下图所示:
图 1. Quartz 核心元素关系图
Quartz 任务调度的核心元素是 scheduler, trigger 和 job,其中 trigger 和 job 是任务调度的元数据, scheduler 是实际执行调度的控制器。scheduler 由 schedulerFactory创建, 默认实现是 StdSchedulerFactory。
4.简单实例
本文为了方便介绍Quartz, 使用springboot来搭建项目,maven的pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<!-- <relativePath></relativePath> -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springboot-job</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<!--代码更简洁-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>添加代码HelloJob
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
/**
* 第一个Quartz Job
* @author 深谷
*/
public class HelloJob implements Job {
private static Logger log = LoggerFactory.getLogger(HelloJob.class);
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.info("HelloJob 任务正在执行,当前时间: {}", Calendar.getInstance().getTime());
}
public static void main(String[] args) throws Throwable {
SchedulerFactory factory = new StdSchedulerFactory();
// 从工厂里面拿到一个scheduler实例
Scheduler scheduler = factory.getScheduler();
String name = "name_1";
// 真正执行的任务并不是Job接口的实例,而是用反射的方式实例化的一个JobDetail实例
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity(name, null).build();
// 定义一个触发器,调度策略是每隔30秒执行一次
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/30 * * * * ?").withMisfireHandlingInstructionDoNothing();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(name, null).withSchedule(cronScheduleBuilder).build();
// 将任务和Trigger放入scheduler
scheduler.scheduleJob(job, trigger);
scheduler.start();
// 休眠一分钟,以便任务可以执行
TimeUnit.MINUTES.sleep(1L);
// scheduler结束
scheduler.shutdown(true);
}
}运行一下,看一下输出
11:36:08.021 logback [main] INFO org.quartz.core.QuartzScheduler[initialize-294] - Scheduler meta-data: Quartz Scheduler (v2.3.0) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
11:36:08.021 logback [main] INFO org.quartz.impl.StdSchedulerFactory[instantiate-1362] - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
11:36:08.021 logback [main] INFO org.quartz.impl.StdSchedulerFactory[instantiate-1366] - Quartz scheduler version: 2.3.0
11:36:08.035 logback [main] INFO org.quartz.core.QuartzScheduler[start-547] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
11:36:30.017 logback [DefaultQuartzScheduler_Worker-1] INFO com.ff.job.HelloJob[execute-21] - HelloJob 任务正在执行,当前时间: Thu Dec 06 11:36:30 CST 2018
11:37:00.004 logback [DefaultQuartzScheduler_Worker-2] INFO com.ff.job.HelloJob[execute-21] - HelloJob 任务正在执行,当前时间: Thu Dec 06 11:37:00 CST 2018
11:37:08.036 logback [main] INFO org.quartz.core.QuartzScheduler[shutdown-666] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.