一、简介
类名 | 描述 |
---|---|
Scheduler | 与调度器交互的主要API (实际上这个就是调度器) |
Job :org.quartz.Job | 希望由调度器执行的组件,是一个接口,也就是我们使用的时候被调度的任务需要实现此接口 |
JobDetail :org.quartz.JobDetail | 用来定义job 的实例 |
Trigger :org.quartz.Trigger | 触发器,定义JobDetail 的执行计划的组件 |
JobBuilder :org.quartz.JobBuilder | 用于定义或者构建JobDetail 执行计划实例 |
TriggerBuilder :org.quartz.TriggerBuilder | 用于定义或者构建Trigger 触发器实例 |
二、SpringBoot
整合Quartz
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2.application.yml
配置
spring:
quartz:
# 持久化-数据库方式存储
job-store-type: jdbc
# 相关属性配置
properties:
org:
quartz:
scheduler:
instanceName: amazonInterfaceScheduler
instanceId: AUTO
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_
isClustered: true
clusterCheckinInterval: 10000
useProperties: false
# sqlserver 启用
selectWithLockSQL: SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?
# 线程池的参数配置
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: false
3.选择数据库初始化sql
三、Quartz
使用
1.Job
和Trigger
一个job
(自定义实现org.quartz.Job
接口的类)可以有多个JobDetail
实例。一个Job可以有多个Trigger
,但一个Trigger
不能对应多个Job
。
1.1、job
Job 指的是你想要执行的任务类,每一个 Job 必须实现
org.quartz.job
接口,且只需要实现接口定义的execute()
方法。在execute
方法内编写任务的业务逻辑。
1.2、Trigger
Trigger用来触发Job的执行。Trigger也有一个关联的
JobDataMap
,可用于将参数传递给由特定Trigger触发的Job实例。Quartz提供了很多不同的Trigger类型,但最常用的是SimpleTrigger
和CronTrigger
。
Trigger
主要包含两种:
SimpleTrigger
CronTrigger
1.3、Cron表达式
Cron
表达式是由7个子表达式组成的字符串,关于 Cron
的各个域的定义如下表格所示:
域 | 是否必填 | 值以及范围 | 通配符 |
---|---|---|---|
秒 | 是 | 0-59 | , - * / |
分 | 是 | 0-59 | , - * / |
时 | 是 | 0-23 | , - * / |
日 | 是 | 1-31 | , - * ? / L W |
月 | 是 | 1-12 或 JAN-DEC | , - * / |
周 | 是 | 1-7 或 SUN-SAT | , - * ? / L # |
年 | 否 | 1970-2099 | , - * / |
运算符 | 含义 |
---|---|
* | 表示匹配该域的任意值,假如在Minutes域使用* , 即表示每分钟都会触发事件。 |
/ | 表示值的增量,从一个值开始,每间隔多少时间后再次执行,可以出现在所有的字段。如在分钟字段上, 0/15表示从0分开始, 间隔15分钟执行一次, 相当于0,15,30,45 |
, | 表示多个值, 可以出现在所有的字段。 如果我们在 “分” 这个域中定义为 8,12,35 ,则表示分别在第8分,第12分 第35分执行该定时任务。 |
- | 表示一个区间。如果我们在 “时” 这个域中定义 1-6 ,则表示在1到6点之间每小时都触发一次。 |
? | 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的8号触发一个操作,但不关心是周几,我们可以这么设置 0 0 0 8 * ? |
L | L是 Last 的缩写, 可以出现在月中的天和周中的天这两个字段, 当时含义不一样。 在月中的天这个字段中, L表示这个月的最后一天。 而在周中的天中, 如果L单独出现, 那么就表示7或者SAT即星期六, 如果出现在一个数字的后面, 那么就表示这个月的周几, 如“6L”, 表示这个月的最后一个周五 |
W | 表示离指定日期的最近那个工作日(周一至周五)触发,只能在 “日” 中使用且只能用在具体的数字之后。若在“日”上置”15W”,表示离每月15号最近的那个工作日触发。假如15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果是 “1W” 就只能往本月的下一个最近的工作日推不能跨月往上一个月推。 |
# | 表示每月的第几个周几,只能作用于 “周” 上。例如 2#3 表示在每月的第三个周二。 |
示例:
0 0/5 * * * ?
:每5分钟执行一次10 0/5 * * * ?
:每5分钟的第10秒的时候执行一次,如:10:00:10, 10:05:10 …0 30 10-13 ? * WED,FRI
:每周三和周五的10:30/11:30/12:30/13:30执行0 0/30 8-9 5,20 * ?
:每月5号和20号的8:00/8:30/9:00/9:30执行
1.4、使用CronTrigger
触发器创建Trigger
实例
CronTrigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(TriggerKey.triggerKey("triggerName", "triggerGroup"))
.withSchedule(CronScheduleBuilder
.cronSchedule(StrUtil.trimToEmpty("0 0/5 * * * ?"))
.withMisfireHandlingInstructionIgnoreMisfires())
.build();
2.Job
和JobDetail
-
Job
和JobDetail
的区分,Job
是指我们具体的「任务类」。JobDetail
指通过JobBuilder
类创建出的一个实例,它和Job
类进行了绑定。 -
Job
实例在Quartz
中的生命周期:每次调度器执行Job
时,它在调用execute
方法前会创建一个新的Job
实例(JobDetail
),当调用完成之后,关联的 Job 对象实例会被释放,释放的实例会被垃圾回收机制回收。 -
JobDetail
:JobDetail
为 Job 实例提供许多设置属性,以及jobDataMap
成员变量属性,它用来存储特定Job
实例的状态信息,调度器需要借助JobDetail
对象来添加Job
实例。
2.1、job
类
public class DumbJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
// 通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据
JobKey key = context.getJobDetail().getKey();
JobDataMap dataMap = context.getMergedJobDataMap();
// TODO:处理逻辑
}
}
2.2、根据job
类创建JobDetail
实例
JobDetail jobDetail = JobBuilder
.newJob(DumbJob.class)
.withIdentity(JobKey.jobKey("jobName", "jobGroup"))
.build();
// 根据jobDetail和trigger注册任务
scheduler.scheduleJob(jobDetail, trigger);
3.Identities
Identities
其实就是调度任务和触发器的身份标识。当Job
和Trigger
注册到Quartz
的调度器中的时候需要定义相应的识别标记(其实就是JobKey
和TriggerKey
)。调度任务和触发器(JobKey
和TriggerKey
)的识别标记中允许使用“分组(group
)”,这对于组织你的工作和触发诸如“报告工作”和“维护工作”等类别是有用的。作业或触发器的键的名称部分必须在组内是惟一的—换句话说,作业或触发器的完整键(或标识符)是名称(name
)和组别(group
)的复合。这里可以先这样理解,JobKey
(name
和group
)是JobDetail
的联合主键,TriggerKey
(name
和group
)是Trigger
的联合主键。
将Job
和 Trigger
注册到 Scheduler
时,可以为它们设置 key
,配置其身份属性。同一个分组下的Job
或 Trigger
的名称必须唯一,即一个 Job
或 Trigger
的 key
由名称(name
)和分组(group
)组成。
4.JobDataMap
4.1、概述
(1).在进行任务调度时JobDataMap
存储在JobExecutionContext
中,非常方便获取。
(2).JobDataMap
可以用来装载任何可以序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它。
(3).JobDataMap
实现了JDK
的Map
接口,并且添加了一些非常方便的方法用来存取数据基本数据类型。
4.2、JobDataMap
放置数据对象
// trigger实例放置
trigger.getJobDataMap().put("triggerData", "triggerDataValue");
// jobDetail实例放置
jobDetail.getJobDataMap().put("jobDetailData", "jobDetailDataValue");
4.3、JobDataMap
获取数据对象
JobExecutionContext
将会合并JobDetail
与Trigger
的JobDataMap
,如果其中属性名相同,后者将覆盖前者。可以使用JobExecutionContext.getMergedJobDataMap()
方法来获取合并后的JobDataMap
。
public class DumbJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
// JobDataMap获取数据对象
String triggerDataValue = (String)context.getMergedJobDataMap().get("triggerData");
// TODO:处理逻辑
}
}
5.Job
的状态与并发
有几个注解,可以添加到Job
实现类上,以影响Quartz
的行为。
-
@DisallowConcurrentExecution
注解可以添加到Job实现类上,告诉Quartz不要同时执行给定Job定义的多个实例(指向该Job
实现类的)。参考上文中提到的例子,假设DumbJob
类添加了这个注解,那么同一时刻只能有一个DumbJob
类的实例在运行。因此,这里所说的不同实例是以
JobDetail
为基础的而不是Job
实现类。之所以要把这个注解添加到Job
实现类上,只是因为Job
实现类的代码修改更方便。 -
@PersistJobDataAfterExecution
注解可以添加到Job
实现类上,告诉Quartz
在execute()
方法成功执行(没有抛异常)后,更新存储的JobDataMap
数据。这样,同一个JobDetail
下次执行时就能获取到更新后的数据了。与@DisallowConcurrentExecution
一样,这个注解也是以JobDetail
为基础区分的,而不是Job
实现类。如果要使用
@PersistJobDataAfterExecution
,强烈建议同时添加@DisallowConcurrentExecution
注解,以避免多个实例同时更新Job
数据。
6.Quartz
执行流程
1、scheduler
是一个计划调度器容器(总部),容器里面可以盛放众多的JobDetail
和trigger
,当容器启动后,里面的每个JobDetail
都会根据trigger
按部就班自动去执行。
2、JobDetail
是一个可执行的工作,它本身可能是有状态的。
3、Trigger
代表一个调度参数的配置,什么时候去调。
4、当JobDetail
和Trigger
在scheduler
容器上注册后,形成了装配好的作业(JobDetail
和Trigger
所组成的一对儿),就可以伴随容器启动而调度执行了。
创建jobDetail
和trigger
–> 根据JobDetail
提供的Job
类型创建一个Job class
的实例 –> 在Scheduler
注册 –> Scheduler
执行Job
时,调用其execute()
方法 –> Job class
的实例被丢弃,Jvm
的垃圾回收器会将它们回收
项目中可以通过配置在
execute()
方法通过反射执行逻辑所在的方法,这样就可以通过配置数据库来实现作业任务了。