简介
What is the Quartz Job Scheduling Library?
Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many enterprise-class features, such as support for JTA transactions and clustering.
Quartz is freely usable, licensed under the Apache 2.0 license.
Quartz Job Scheduling Library是什么? Quartz是功能强大的开源作业调度库,几乎可以集成到任何Java应用程序中-从最小的独立应用程序到最大的电子商务系统。 Quartz可用于创建简单或复杂的计划,以执行数以十计,百计,万计的工作。任务标准Java组件的任务,都可以执行您对其执行的任何编程操作。Quartz Scheduler包含许多企业级功能,例如对JTA事务和集群的支持。
Quartz是免费使用的,并根据Apache 2.0许可获得许可。
Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。官网地址:http://www.quartz-scheduler.org/Quartz
用一个小Java库发布文件(.jar文件),这个库文件包含了所有Quartz核心功能。这些功能的主要接口(API)是Scheduler接口。它提供了简单的操作,例如:将任务纳入日程或者从日程中取消,开始/停止/暂停日程进度。
功能
持久性任务 - 就是保持调度定时的状态;
任务管理 - 对调度任务进行有效的管理,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。;
例如:
自动关闭30分钟未支付的订单
与第三方公司对账业务
数据统计,比如博客系统统计日粉丝数,日阅读量等
活动开始和结束通知;
想在每月25号,自动还款;
每周或者每月的提醒事项,比如周总结或者月总结;
像这种某个时间点执行任务,或者每隔一段时间重复执行任务,都可以用Quartz实现
特点
强大的调度功能,例如丰富多样的调度方法,可以满足各种常规和特殊需求;
灵活的应用方式,例如支持任务调度和任务的多种组合,支持调度数据的多种存储方式(DB,RAM等);
类型
优点
缺点
RAMJobStore
不要外部数据库,配置容易,运行速度快
因为调度程序信息是存储在被分配给JVM的内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。另外因为存储到JVM内存里面,所以可以存储多少个Job和Trigger将会受到限制
JDBCJobStore
支持集群,因为所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应用服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启而导致执行失败的任务
运行速度的快慢取决与连接数据库的快慢
支持分布式集群,具有伸缩性和高可用性,支持负载均衡。
完全由Java写成,方便集成(Spring)
当然除开Quartz我们也可以使用这些工具来完成任务的管理:
java.util.Timer:一个 JDK 中自带的处理简单定时任务的工具
java.util.concurrent.ScheduledExecutorService:JDK 中的定时任务接口,可以将定时任务与线程池功能结合使用
org.springframework.scheduling.annotation.Scheduled:Spring 框架中基于注解来实现定时任务处理。
核心组件
Quartz框架内部主要类的关系如下:
下面我们主要介绍Scheduler、Job 、JobDetail、Trigger四个类
Job类
首先我们需要定义实现一个定时功能的接口,我们可以称之为Task(或Job),如定时发送邮件的task(Job),重启机器的task(Job),优惠券到期发送短信提醒的task(Job)。
即表示要执行的具体工作或者被调度的任务。我们的任务类实现该接口,重写execute方法来定义任务的执行逻辑。主要有两种类型的job:无状态的(stateless)和有状态的(stateful)。对于同一个trigger来说,有状态的job不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。Job主要有两种属性:volatility和durability,其中volatility表示任务是否被持久化到数据库存储,而durability表示在没有trigger关联的时候任务是否被保留。两者都是在值为true的时候任务被持久化或保留。一个job可以被多个trigger关联,但是一个trigger只能关联一个job。
例如:
1 2 3 4 5 6 7 8 9 10 import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;public class AlphaJob implements Job { @Override public void execute (JobExecutionContext context) throws JobExecutionException { System.out.println(Thread.currentThread().getName() + ": execute a quartz job." ); } }
JobDetail类
JobDetail定义任务详情。包含执行任务的Job,任务的一些身份信息(可以帮助找到这个任务),给任务设置JobDataMap(把参数带到任务里面去)。JobDetail里面常用方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public interface JobDetail { public JobKey getKey () ; public String getDescription () ; public Class<? extends Job > getJobClass(); public JobDataMap getJobDataMap () ; public boolean isDurable () ; public boolean isPersistJobDataAfterExecution () ; public boolean isConcurrentExectionDisallowed () ; public boolean requestsRecovery () ; public JobBuilder getJobBuilder () ; }
JobDetail实例一般是通过JobBuilder来创建(Build模式)。例如,我们定义一个简单的JobDetail,Job执行逻辑类是AlphaJob类,Job名字是AlphaJob,Job组是groupName**(job名字和job组是job的唯一标识)**。同时我们还给job传递了一个字符串参数AlphaJob。
1 2 3 4 5 6 7 JobDetail jobDetail = JobBuilder .newJob(AlphaJob.class) .withIdentity("Alpha" , "groupName" ) .build(); JobDataMap map = jobDetail.getJobDataMap();map.put("JOB_NAME" , "AlphaJob" );
Trigger类
Trigger触发器,设置Job什么时候执行。
触发器
试用场景
SimpleTrigger
简单触发器,适用于 按指定的时间间隔执行多少次任务的情况
CronTrigger
Cron触发器,通过Cron表达式来控制任务的执行时间
DailyTimeIntervalTrigger
日期触发器,在给定的时间范围内或指定的星期内以秒、分钟或者小时为周期进行重复的情况
CalendarIntervalTrigger
日历触发器,根据一个给定的日历时间进行重复
PS: 一个Trigger只能绑定一个Job。但是一个Job可以被多个Trigger绑定。
最常用的有:
SimpleTrigger
用来触发只需执行一次或者在给定时间触发并且重复N次且每次执行延迟一定时间的任务。
SimpleTrigger由SimpleScheduleBuilder构建生成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 public static SimpleScheduleBuilder repeatMinutelyForever () ;public static SimpleScheduleBuilder repeatMinutelyForever (int minutes) ;public static SimpleScheduleBuilder repeatSecondlyForever () ;public static SimpleScheduleBuilder repeatSecondlyForever (int seconds) ;public static SimpleScheduleBuilder repeatHourlyForever () ;public static SimpleScheduleBuilder repeatHourlyForever (int hours) ;public static SimpleScheduleBuilder repeatMinutelyForTotalCount (int count) ;public static SimpleScheduleBuilder repeatMinutelyForTotalCount (int count, int minutes) ;public static SimpleScheduleBuilder repeatSecondlyForTotalCount (int count) ;public static SimpleScheduleBuilder repeatSecondlyForTotalCount (int count, int seconds) ;public static SimpleScheduleBuilder repeatHourlyForTotalCount (int count) ;public static SimpleScheduleBuilder repeatHourlyForTotalCount (int count, int hours) ;public SimpleScheduleBuilder withIntervalInMilliseconds (long intervalInMillis) ;public SimpleScheduleBuilder withIntervalInSeconds (int intervalInSeconds) ;public SimpleScheduleBuilder withIntervalInMinutes (int intervalInMinutes) ;public SimpleScheduleBuilder withIntervalInHours (int intervalInHours) ;public SimpleScheduleBuilder withRepeatCount (int triggerRepeatCount) ;public SimpleScheduleBuilder repeatForever () ;public SimpleScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires () { misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY; return this ; } public SimpleScheduleBuilder withMisfireHandlingInstructionFireNow () { misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW; return this ; } public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithExistingCount () { misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT; return this ; } public SimpleScheduleBuilder withMisfireHandlingInstructionNextWithRemainingCount () { misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT; return this ; } public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithExistingCount () { misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT; return this ; } public SimpleScheduleBuilder withMisfireHandlingInstructionNowWithRemainingCount () { misfireInstruction = SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT; return this ; }
例如,定义一个触发器,每隔30S执行一次,总共执行100次:
1 2 3 4 5 6 7 SimpleTrigger trigger = TriggerBuilder .newTrigger() .withIdentity(jobName, jobGroupName) .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(30 , 100 )) .startNow() .build();
CronTrigger
按照日历触发,例如“每个周五”,每个月10日中午或者10:15分。
CronTrigger使用Cron表达是来定义任务的触发时间。相对来说比较灵活,对于复杂的业务需求来说更加的实用。CronTrigger由CronScheduleBuilder构建而成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 public static CronScheduleBuilder cronSchedule (String cronExpression) ;public static CronScheduleBuilder cronScheduleNonvalidatedExpression ( String cronExpression) throws ParseException;public static CronScheduleBuilder cronSchedule (CronExpression cronExpression) ;public static CronScheduleBuilder dailyAtHourAndMinute (int hour, int minute) ;public static CronScheduleBuilder atHourAndMinuteOnGivenDaysOfWeek ( int hour, int minute, Integer... daysOfWeek) ;public static CronScheduleBuilder weeklyOnDayAndHourAndMinute ( int dayOfWeek, int hour, int minute) ;public static CronScheduleBuilder monthlyOnDayAndHourAndMinute ( int dayOfMonth, int hour, int minute) ;public CronScheduleBuilder inTimeZone (TimeZone timezone) ;public CronScheduleBuilder withMisfireHandlingInstructionIgnoreMisfires () { misfireInstruction = Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY; return this ; } public CronScheduleBuilder withMisfireHandlingInstructionDoNothing () { misfireInstruction = CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING; return this ; } public CronScheduleBuilder withMisfireHandlingInstructionFireAndProceed () { misfireInstruction = CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW; return this ; }
Cron表达式规则如下:
1 [秒] [分] [时] [日] [月] [周] [年]
通常定义 “年” 的部分可以省略,实际常用的由 前六部分组成
关于 cron 的各个域的定义如下表格所示:
域
是否必填
值以及范围
通配符
秒
是
0-59
, - * /
分
是
0-59
, - * /
时
是
0-23
, - * /
日
是
1-31
, - * ? / L W
月
是
1-12 或 JAN-DEC
, - * /
周
是
1-7 或 SUN-SAT
, - * ? / L #
年
否
1970-2099
, - * /
,
这里指的是在两个以上的时间点中都执行,如果我们在 “分” 这个域中定义为 8,12,35
,则表示分别在第8分,第12分 第35分执行该定时任务。
-
这个比较好理解就是指定在某个域的连续范围,如果我们在 “时” 这个域中定义 1-6
,则表示在1到6点之间每小时都触发一次,用 ,
表示 1,2,3,4,5,6
*
表示所有值,可解读为 “每”。 如果在“日”这个域中设置 *
,表示每一天都会触发。
?
表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的8号触发一个操作,但不关心是周几,我们可以这么设置 0 0 0 8 * ?
/
在某个域上周期性触发,该符号将其所在域中的表达式分为两个部分,其中第一部分是起始值,除了秒以外都会降低一个单位,比如 在 “秒” 上定义 5/10
表示从 第 5 秒开始 每 10 秒执行一次,而在 “分” 上则表示从 第 5 秒开始 每 10 分钟执行一次。
L
表示英文中的LAST 的意思,只能在 “日”和“周”中使用。在“日”中设置,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年), 在“周”上表示周六,相当于”7”或”SAT”。如果在”L”前加上数字,则表示该数据的最后一个。例如在“周”上设置”7L”这样的格式,则表示“本月最后一个周六”
W
表示离指定日期的最近那个工作日(周一至周五)触发,只能在 “日” 中使用且只能用在具体的数字之后。若在“日”上置”15W”,表示离每月15号最近的那个工作日触发。假如15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果是 “1W” 就只能往本月的下一个最近的工作日推不能跨月往上一个月推。
#
表示每月的第几个周几,只能作用于 “周” 上。例如 ”2#3” 表示在每月的第三个周二。
举例如下:
使用CronTrigger例子如下:
1 2 3 4 5 String cronExpression = String.format("0 %d %d ? * *" , 15 , 30 );CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(jobName, jobGroupName) .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build();
定义一个每个礼拜星期六,15:30执行的任务,代码如下:
1 2 3 4 5 CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(jobName, jobGroupName) .withSchedule(CronScheduleBuilder.weeklyOnDayAndHourAndMinute(DateBuilder.SATURDAY, 15 , 30 )) .build();
Scheduler类
任务调度器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。正常情况下一个应用只需要一个Scheduler对象。
Scheduler 由 SchedulerFactory 创建:DirectSchedulerFactory或者StdSchedulerFactory。第二种工厂StdSchedulerFactory使用较多,因为DirectSchedulerFactory使用起来不够方便,需要作许多详细的手工编码设置。Scheduler主要有三种:RemoteMBeanScheduler,RemoteScheduler和StdScheduler。
Scheduler调度器,是Quartz框架的心脏,用来管理Trigger和Job,并保证Job能在Trigger设置的时间被触发执行。一般情况下调度器启动之后,我们不需要做任何处理。
Scheduler主要函数介绍如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 List<JobExecutionContext> getCurrentlyExecutingJobs () throws SchedulerException; ListenerManager getListenerManager () throws SchedulerException; Date scheduleJob (JobDetail jobDetail, Trigger trigger) throws SchedulerException; Date scheduleJob (Trigger trigger) throws SchedulerException; void scheduleJobs (Map<JobDetail, Set<? extends Trigger>> triggersAndJobs, boolean replace) throws SchedulerException;void scheduleJob (JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace) throws SchedulerException;boolean unscheduleJob (TriggerKey triggerKey) throws SchedulerException; boolean unscheduleJobs (List<TriggerKey> triggerKeys) throws SchedulerException; Date rescheduleJob (TriggerKey triggerKey, Trigger newTrigger) throws SchedulerException; void addJob (JobDetail jobDetail, boolean replace) throws SchedulerException; void addJob (JobDetail jobDetail, boolean replace, boolean storeNonDurableWhileAwaitingScheduling) throws SchedulerException; boolean deleteJob (JobKey jobKey) throws SchedulerException; boolean deleteJobs (List<JobKey> jobKeys) throws SchedulerException; void triggerJob (JobKey jobKey) throws SchedulerException; void triggerJob (JobKey jobKey, JobDataMap data) throws SchedulerException; void pauseJob (JobKey jobKey) throws SchedulerException; void pauseJobs (GroupMatcher<JobKey> matcher) throws SchedulerException;void pauseTrigger (TriggerKey triggerKey) throws SchedulerException; void pauseTriggers (GroupMatcher<TriggerKey> matcher) throws SchedulerException;void resumeJob (JobKey jobKey) throws SchedulerException; void resumeJobs (GroupMatcher<JobKey> matcher) throws SchedulerException;void resumeTrigger (TriggerKey triggerKey) throws SchedulerException; void resumeTriggers (GroupMatcher<TriggerKey> matcher) throws SchedulerException;void pauseAll () throws SchedulerException;void resumeAll () throws SchedulerException;List<String> getJobGroupNames () throws SchedulerException; Set<JobKey> getJobKeys (GroupMatcher<JobKey> matcher) throws SchedulerException; List<? extends Trigger > getTriggersOfJob(JobKey jobKey) throws SchedulerException; List<String> getTriggerGroupNames () throws SchedulerException; Set<TriggerKey> getTriggerKeys (GroupMatcher<TriggerKey> matcher) throws SchedulerException; Set<String> getPausedTriggerGroups () throws SchedulerException; JobDetail getJobDetail (JobKey jobKey) throws SchedulerException; Trigger getTrigger (TriggerKey triggerKey) throws SchedulerException; Trigger.TriggerState getTriggerState (TriggerKey triggerKey) throws SchedulerException; void resetTriggerFromErrorState (TriggerKey triggerKey) throws SchedulerException; void addCalendar (String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException; boolean deleteCalendar (String calName) throws SchedulerException;Calendar getCalendar (String calName) throws SchedulerException; List<String> getCalendarNames () throws SchedulerException; boolean interrupt (JobKey jobKey) throws UnableToInterruptJobException;boolean interrupt (String fireInstanceId) throws UnableToInterruptJobException;boolean checkExists (JobKey jobKey) throws SchedulerException;boolean checkExists (TriggerKey triggerKey) throws SchedulerException;
Quartz 集群
Quartz的集群部署方案在架构上是分布式的,没有负责集中管理的节点,而是利用数据库锁的方式来实现集群环境下进行并发控制。通过基于数据库对分布式锁来达到并发控制对目的。
数据库核心表如下:
Table Name
Description
QRTZ_CALENDARS
存储Quartz的Calendar信息
QRTZ_CRON_TRIGGERS
存储CronTrigger,包括Cron表达式和时区信息
QRTZ_FIRED_TRIGGERS
存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息
QRTZ_PAUSED_TRIGGER_GRPS
存储已暂停的Trigger组的信息
QRTZ_SCHEDULER_STATE
存储少量的有关Scheduler的状态信息,和别的Scheduler实例
QRTZ_LOCKS
存储程序的悲观锁的信息
QRTZ_JOB_DETAILS
存储每一个已配置的Job的详细信息
QRTZ_JOB_LISTENERS
存储有关已配置的JobListener的信息
QRTZ_SIMPLE_TRIGGERS
存储简单的Trigger,包括重复次数、间隔、以及已触的次数
QRTZ_BLOG_TRIGGERS
Trigger作为Blob类型存储
QRTZ_TRIGGER_LISTENERS
存储已配置的TriggerListener的信息
QRTZ_TRIGGERS
存储已配置的Trigger的信息
其中,QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,其表结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 CREATE TABLE `QRTZ_LOCKS` ( `LOCK_NAME` varchar (40 ) NOT NULL , PRIMARY KEY (`LOCK_NAME`) ) ENGINE= InnoDB DEFAULT CHARSET= utf8; + | LOCK_NAME | + | CALENDAR_ACCESS | | JOB_ACCESS | | MISFIRE_ACCESS | | STATE_ACCESS | | TRIGGER_ACCESS | +
可以看出QRTZ_LOCKS中有5条记录,代表5把锁,分别用于实现多个Quartz Node对Job、Trigger、Calendar访问的同步控制。
QuartzScheduler调度线程不断获取trigger,触发trigger,释放trigger,流程如下:
每当要进行与某种业务相关的数据库操作时,先去QRTZ_LOCKS表中查询操作相关的业务对象所需要的锁,在select语句之后加for update来实现。例如,TRIGGER_ACCESS表示对任务触发器相关的信息进行修改、删除操作时所需要获得的锁。这时,执行查询这个表数据的SQL形如:
1 select * from QRTZ_LOCKS t where t.lock_name= 'TRIGGER_ACCESS' for update
当一个线程使用上述的SQL对表中的数据执行查询操作时,若查询结果中包含相关的行,数据库就对该行进行ROW LOCK ;若此时,另外一个线程使用相同的SQL对表的数据进行查询,由于查询出的数据行已经被数据库锁住了,此时这个线程就只能等待 ,直到拥有该行锁的线程完成了相关的业务操作,执行了commit动作后,数据库才会释放了相关行的锁,这个线程才能继续执行。
通过这样的机制,在集群环境下,结合悲观锁 的机制就可以防止一个线程对数据库数据的操作的结果被另外一个线程所覆盖,从而可以避免一些难以觉察的错误发生。当然,达到这种效果的前提是需要把Connection设置为手动提交,即autoCommit为false。
在Spring Boot中使用Quartz
在Spring Boot中,相关类的配置被大大的简化,主要有以下几部分操作:
导入依赖
我们在项目的pom.xml
文件中添加Quartz的相关依赖
1 2 3 4 5 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-quartz</artifactId > </dependency >
配置Quartz
我们在application.properties
中对Quartz进行相关配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 spring.quartz.job-store-type =jdbc spring.quartz.scheduler-name =communityScheduler spring.quartz.properties.org.quartz.scheduler.instanceId =AUTO spring.quartz.properties.org.quartz.jobStore.class =org.quartz.impl.jdbcjobstore.JobStoreTX spring.quartz.properties.org.quartz.jobStore.driverDelegateClass =org.quartz.impl.jdbcjobstore.StdJDBCDelegate spring.quartz.properties.org.quartz.jobStore.isClustered =true spring.quartz.properties.org.quartz.threadPool.class =org.quartz.simpl.SimpleThreadPool spring.quartz.properties.org.quartz.threadPool.threadCount =5
创建Job类实例
代码类似同上:
1 2 3 4 5 6 7 8 9 10 import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;public class AlphaJob implements Job { @Override public void execute (JobExecutionContext context) throws JobExecutionException { System.out.println(Thread.currentThread().getName() + ": execute a quartz job." ); } }
创建Configuration类
直接在代码里注册JobDetail和Trigger的bean就可以了
只要已启动服务,配置文件默认会被加载,Quartz根据相关配置对数据库进行写入,同时调度器Scheduler也会根据数据进行调度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import org.quartz.JobDataMap;import org.quartz.JobDetail;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.quartz.JobDetailFactoryBean;import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;@Configuration public class QuartzConfig { @Bean public JobDetailFactoryBean alphaJobDetail () { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean (); factoryBean.setJobClass(AlphaJob.class); factoryBean.setName("alphaJob" ); factoryBean.setGroup("alphaJobGroup" ); factoryBean.setDurability(true ); factoryBean.setRequestsRecovery(true ); return factoryBean; } @Bean public SimpleTriggerFactoryBean alphaTrigger (JobDetail alphaJobDetail) { SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean (); factoryBean.setJobDetail(alphaJobDetail); factoryBean.setName("alphaTrigger" ); factoryBean.setGroup("alphaTriggerGroup" ); factoryBean.setRepeatInterval(3000 ); factoryBean.setJobDataMap(new JobDataMap ()); return factoryBean; } @Bean public JobDetailFactoryBean postScoreRefreshJobDetail () { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean (); factoryBean.setJobClass(PostScoreRefreshJob.class); factoryBean.setName("postScoreRefreshJob" ); factoryBean.setGroup("communityJobGroup" ); factoryBean.setDurability(true ); factoryBean.setRequestsRecovery(true ); return factoryBean; } @Bean public SimpleTriggerFactoryBean postScoreRefreshTrigger (JobDetail postScoreRefreshJobDetail) { SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean (); factoryBean.setJobDetail(postScoreRefreshJobDetail); factoryBean.setName("postScoreRefreshTrigger" ); factoryBean.setGroup("communityTriggerGroup" ); factoryBean.setRepeatInterval(1000 * 60 * 5 ); factoryBean.setJobDataMap(new JobDataMap ()); return factoryBean; } }