1 Quartz 简介
Quartz 是基于Java 实现的一个开源的调度框架, 是开源组织OpenSymphony 的产品。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。官方网站: 。
本人在产品开发中使用的是版本 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文件如下:
复制代码 org.springframework.boot spring-boot-starter-parent 1.5.6.RELEASE 4.0.0 springboot-job org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.quartz-scheduler quartz 2.3.0 org.projectlombok lombok 1.16.14 compile
添加代码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.011: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 201811:37:00.004 logback [DefaultQuartzScheduler_Worker-2] INFO com.ff.job.HelloJob[execute-21] - HelloJob 任务正在执行,当前时间: Thu Dec 06 11:37:00 CST 201811:37:08.036 logback [main] INFO org.quartz.core.QuartzScheduler[shutdown-666] - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.复制代码