项目主页
帮助文档
Quartz Enterprise Job Scheduler
Quartz 分布式配置
Spring整合Quartz定时任务 在集群、分布式系统中的应用
JDK 1.3 开始通过 java.util.Timer 和 java.util.TimerTask 提供了简单的任务调度功能,允许用户调度一个按固定时间间隔运行的任务,但是对于复杂任务调度业务实现起来还是很麻烦;
OpenSymphony 提供的 Quartz 开源库在此基础上,提供了复杂灵活的任务调度功能,使用 quertz 需要导入以下依赖:
org.quartz-scheduler:quartz
Quartz 对于任务调度进行了高度抽象,提出了调度器、任务、触发器3个核心的概念,并提供了以下的接口和实现类进行支持:
Job
用于定义需要执行的任务,JobExecutionContext 类提供了调度上下文的信息,JobDataMap 用于保存 Job 运行时的信息;
JobDetail
用于描述 Job 的事项类及其相关的静态信息,这是由于 Quartz 每次执行 Job 时,都会重新创建一个新的 Job 实例,因此需要一个类用于反射实例化 Job;
Trigger
用于描述触发 Job 执行的时间触发规则,主要有以下2个实现类:
一个 Trigger 只能对应一个 Job,一个 Job 可以对应多个 Trigger;
Calendar
用于描述一些特定时间点的集合,可以看成 java.util.Calendar 时间点的集合;一个 Trigger 可以与多个 Calendar 关联,org.quartz.impl.calendar 包下提供了 Calendar 的几个实现类:AnnualCalendar、MonthlyCalendar、WeeklyCalendar 分别针对每年、每月、每周进行定义;
Scheduler
用于代表一个 Quartz 的独立运行容器,Trigger 和 JobDetail 可以注册到 Schedular 中;
ThreadPool
Schedular 使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程来提高运行效率;

以下是 Quartz 的快速使用示例,示例的 quartz 版本为 2.2.3,示例代码地址:https://gitee.com/assad/springframework-test-quartz/tree/master/src/main/java/site/assad/basicQuartzTest
public class HelloJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDetail jobDetail = context.getJobDetail();
System.out.println("["+jobDetail.getKey().getName() + ","
+jobDetail.getKey().getGroup() +"] "
+"Hello world! "
+ new Date());
}
}
SimpleTrigger 的使用示例
//通过工厂方法创建Scheduler
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//创建 JobDetail
JobDetail jobDetail = newJob(HelloJob.class) //指定实现类类型
.withIdentity("job1","group1") //指定identity
.build();
//创建 Trigger
SimpleTrigger simpleTrigger =(SimpleTrigger)newTrigger()
.withIdentity("trigger1","group1") //指定 identity
.startAt(new Date()) //指定启动时间,如果为现在启动,使用.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(5) //指定循环间隔时间,可以 withIntervalInMinutes,withIntervalInHours
.repeatForever()) //指定循环次数,无限循环,可以.withRepeatCount(200) 指定固定循环次数
.endAt(dateOf(19,0,0)) //停止时间为当天的 19:00:00,可选
.build();
//在 scheduler 绑定 jobDetail 和 trigger
scheduler.scheduleJob(jobDetail,simpleTrigger);
//启动 scheduler
scheduler.start();
CronTrigger 的使用示例
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
JobDetail jobDetail = newJob(HelloJob.class)
.withIdentity("job2","group1")
.build();
CronTrigger cronTriggerr = (CronTrigger)newTrigger()
.withIdentity("trigger2","group1")
.withSchedule(cronSchedule("0/5 * * * * ?")) //指定 cron 表达式:每分钟从0s开始,间隔5s执行
.build();
scheduler.scheduleJob(jobDetail,cronTriggerr);
scheduler.start();
Quartz 使用的 CronTrigger 使用类似 Linux 的 Cron 表达式定义时间规则,一个典型的 Cron 表达式由 6 或 7 个空格分隔的字段组成,如表达式 “0 0 12 * * ?” 表示每一天的12:00 这一个时刻,具体每一段的规则如下:

※ 注意星期1表示周日,7表示周六;
※ Cron表达式对大小写不敏感;
其中个各个特殊符号的含义如下:

以下是一些示例:

在 Quartz 中可以使用 org.quartz.impl.calendar.Calendar 排除一些特殊的日期,如节假日等,一个示例如下:
//以下要执行一个任务,每1小时执行一次,将国庆节10.1-10.7排除在外
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
JobDetail jobDetail = newJob(HelloJob.class)
.withIdentity("job1","group1")
.build();
//设定 Calendar 集合
AnnualCalendar holidays = new AnnualCalendar();
ArrayList<Calendar> nationDayList = new ArrayList<>();
for(int i=1;i<=7;i++){
Calendar nationDay = new GregorianCalendar();
nationDay.add(Calendar.MONTH,10);
nationDay.add(Calendar.DATE,i++);
}
holidays.setDaysExcluded(nationDayList); //设置每年执行集合的排除时间规则
SimpleTrigger simpleTrigger = (SimpleTrigger) newTrigger()
.withIdentity("job3","group1")
.startAt(dateOf(19,5,0,19,1,2017)) //在 2017-1-19 19:05:00 开始执行
.withSchedule(simpleSchedule()
.withIntervalInHours(1)
.repeatForever()
)
.build();
scheduler.scheduleJob(jobDetail,simpleTrigger);
scheduler.start();
Quartz的默认调度信息保存在内存中,可以通过修改配置文件来修改调度信息的保存策略,同时还可以修改一些运行参数;
默认的配置文件位于 Quartz JAR 包下 org.quartz 的 quartz.properties ;如果要覆盖其配置信息,只需要在项目的根目录下创建一个 quartz.properties 即可;
默认的部分配置如下:
# 配置调度器的线程池
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
# 配置任务调度现场数据保存机制:直接保存在内存中
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
以下配置将调度信息使用Mysql数据库作为持久化保存策略:
# 配置任务调度现场数据保存机制:使用数据库持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix = QUTZ_
org.quartz.jobStore.dataSource = qzDS
# 定义具体数据源的配置属性,这里使用 Mysql
org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL = jdbc:mysql://localhost:3306/sampledb
org.quartz.dataSource.qzDS.user = root
org.quartz.dataSource.qzDS.password = 123456
org.quartz.dataSource.qzDS.maxConnections = 30
注意 Quartz 是使用 JDBC 作为持久化层的,项目中需要导入 Mysql-JDBC 驱动依赖;
如果使用数据库保存调度信息,Quartz 支持从数据库中恢复被中断的任务,如下示例恢复定位为 group1.trigger1 的触发器相关的任务:
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//获取定位为“group1.trigger1”的 Trigger
SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(TriggerKey.triggerKey("trigger1","group1"));
//恢复运行指定的 Trigger
scheduler.rescheduleJob(trigger.getKey(),trigger);
scheduler.start();