一、Quartz简介
用过Quartz的都懂,Quartz就是一个完全由java编写的开源作业调度框架。
1、组件简介
需要使用这个框架需要知道几个词。
Job
Job
是一个任务接口,开发者定义自己的任务须实现该接口,并重写execute(JobExecutionContext context)
方法.Job
中的任务有可能并发执行,例如任务的执行时间过长,而每次触发的时间间隔太短,则会导致任务会被并发执行。- 为了避免出现上面的问题,可以在
Job
实现类上使用@DisallowConcurrentExecution
,保证上一个任务执行完后,再去执行下一个任务
JobDetail
JobDetail
是任务详情。- 包含有:任务名称,任务组名称,任务描述、具体任务Job的实现类、参数配置等等信息
- 可以说
JobDetail
是任务的定义,而Job
是任务的执行逻辑。
Trigger
- Trigger是一个触发器,定义Job执行的时间规则。
- 主要触发器:
SimpleTrigger
,CronTrigger
,CalendarIntervalTrigger
,DailyTimeIntervalTrigger
。 SimpleTrigger
:从某一个时间开始,以一定的时间间隔来执行任务,重复多少次。CronTrigger
: 适合于复杂的任务,使用cron表达式来定义执行规则。CalendarIntervalTrigger
:指定从某一个时间开始,以一定的时间间隔执行的任务,时间间隔比SimpleTrigger
丰富DailyTimeIntervalTrigger
:指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。- 所有的Trigger都包含了
StartTime
和endTime
这两个属性,用来指定Trigger
被触发的时间区间。 - 所有的Trigger都可以设置
MisFire
策略. MisFire
策略是对于由于系统奔溃或者任务时间过长等原因导致Trigger在应该触发的时间点没有触发.- 并且超过了
misfireThreshold
设置的时间(默认是一分钟,没有超过就立即执行)就算misfire(失火)了。 - 这个时候就该设置如何应对这种变化了。激活失败指令(
Misfire Instructions
)是触发器的一个重要属性
发生Misfire 对于SimpleTrigger的处理策略
//将任务马上执行一次。对于不会重复执行的任务,这是默认的处理策略。 |
发生Misfire 对于其他的Trigger
//立刻执行一次,然后就按照正常的计划执行。 |
Scheduler
- 调度器,主要是用来管理
Trigger
、JobDetail
的。 Scheduler
可以通过组名或者名称来对Trigger
和JobDetail
来进行管理- 一个
Trigger
只能对应一个Job
,但是一个Job
可以对应多个Trigger
. Scheduler
有两个实现类:RemoteScheduler
、StdScheduler
。但它是由SchdulerFactory
创建的。SchdulerFactory
是个接口,它有两个实现类:StdSchedulerFactory
、DirectSchedulerFactory
2、相关Builder介绍
Quartz提供了相应的Builder方便我们进行构造。
JobBuilder
这个主要方便我们构建任务详情,常用方法:
withIdentity(String name, String group)
:配置Job名称与组名withDescription(String jobDescription)
: 任务描述requestRecovery()
: 出现故障是否重新执行,默认falsestoreDurably()
: 作业完成后是否保留存储,默认falseusingJobData(String dataKey, String value)
: 配置单个参数keyusingJobData(JobDataMap newJobDataMap)
: 配置多个参数,放入一个mapsetJobData(JobDataMap newJobDataMap)
: 和上面类似,但是这个参数直接指向newJobDataMap,直接设置的参数无效
TriggerBuilder
这个主要方便我们构建触发器,常用方法:
withIdentity(String name, String group)
: 配置Trigger名称与组名withIdentity(TriggerKey triggerKey)
: 配置Trigger名称与组名withDescription(String triggerDescription)
: 描述withPriority(int triggerPriority)
: 设置优先级,默认是:5startAt(Date triggerStartTime)
: 设置开始时间startNow()
: 触发器立即生效endAt(Date triggerEndTime)
: 设置结束时间withSchedule(ScheduleBuilder<SBT> schedBuilder)
: 设置调度builder,下面的builder就是
SimpleScheduleBuilder
几种触发器类型之一,最简单常用的。常用方法:
repeatForever()
:指定触发器将无限期重复withRepeatCount(int triggerRepeatCount)
:指定重复次数,总触发的次数=triggerRepeatCount+1repeatSecondlyForever(int seconds)
:每隔seconds秒无限期重复repeatMinutelyForever(int minutes)
:每隔minutes分钟无限期重复repeatHourlyForever(int hours)
:每隔hours小时无限期重复repeatSecondlyForever()
:每隔1秒无限期重复repeatMinutelyForever()
:每隔1分钟无限期重复repeatHourlyForever()
:每隔1小时无限期重复withIntervalInSeconds(int intervalInSeconds)
:每隔intervalInSeconds秒执行withIntervalInMinutes(int intervalInMinutes)
:每隔intervalInMinutes分钟执行withIntervalInHours(int intervalInHours)
:每隔intervalInHours小时执行withMisfireHandlingInstructionFireNow()
:失火后的策略为:MISFIRE_INSTRUCTION_FIRE_NOW
CronScheduleBuilder
算是非常常用的了,crontab 表达式,常用方法:
cronSchedule(String cronExpression)
:使用cron表达式
简单的一笔
CalendarIntervalScheduleBuilder
常用方法:
inTimeZone(TimeZone timezone)
:设置时区withInterval(int timeInterval, IntervalUnit unit)
:相隔多少时间执行,单位有:毫秒、秒、分、时、天、周、月、年withIntervalInSeconds(int intervalInSeconds)
:相隔秒withIntervalInWeeks(int intervalInWeeks)
:相隔周withIntervalInMonths(int intervalInMonths)
:相隔月
等等方法
DailyTimeIntervalScheduleBuilder
withInterval(int timeInterval, IntervalUnit unit)
:相隔多少时间执行,单位有:秒、分、时,其他单位的不支持会报错withIntervalInSeconds(int intervalInSeconds)
:相隔秒withIntervalInMinutes(int intervalInMinutes)
:相隔分withIntervalInHours(int intervalInHours)
:相隔时onDaysOfTheWeek(Set<Integer> onDaysOfWeek)
:将触发器设置为在一周的指定日期触发。取值范围可以是1-7,1是星期天,2是星期一…onDaysOfTheWeek(Integer ... onDaysOfWeek)
:和上面一样,3是星期二…7是星期六onMondayThroughFriday()
:每星期的周一导周五触发onSaturdayAndSunday()
:每星期的周六周日触发onEveryDay()
:每天触发withRepeatCount(int repeatCount)
:重复次数,总的重复次数=1 (at start time) + repeatCount
startingDailyAt(TimeOfDay timeOfDay)
:触发的开始时间endingDailyAt(TimeOfDay timeOfDay)
:触发的结束时间
3、基本使用
引用jar,就可以玩了。
引用依赖
<dependency> |
在pom.xml文件中,引入
简单例子:
public class Demo { |
是不是感觉很简单,自己定义一个类,然后实现Job
接口,重写execute(JobExecutionContext context)
方法,然后使用调度器去调度一下即可。
简单玩完了,和springboot整合一波。
二、与Springboot整合
这个才是重点,Springboot基本是一个Java程序猿必备的技能了。什么框架都得和它整一下。
1、引入依赖
<dependency> |
spring官方自己都帮我们搞好了一些配置。
2、配置application.yml
如下:
spring: |
- 这里打算搞个集群版的,就算你部署多台服务器,定时任务会自己负载均衡,不会每台服务器都执行。
- 表的生成,其实可以修改配置,启动的时候自己在数据库生成表。操作方法:
- 修改:
spring.quartz.jdbc.initialize-schema: ALWAYS
、说明一下 - 这里有3个值可选:
ALWAYS
(每次都生成)、EMBEDDED
(仅初始化嵌入式数据源)、NEVER
(不初始化数据源)。 - 表生成之后,再改为never即可。注意一点就是我测试了下,发现只有使用
druid
数据库连接池才会自动生成表
3、表的说明
会自动生成的表如下:
//以Blob 类型存储的触发器。 |
重要表字段解析
CREATE TABLE `qrtz_job_details` ( |
4、怎么使用
- 当我们引入
spring-boot-starter-quartz
的依赖后,springboot在启动的时候会自动加载配置类:org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration
。 - 会帮我们初始化好调度器,源码:
SchedulerFactoryBean
实现InitializingBean
,重写afterPropertiesSet()
里面就有了。 - 而且Scheduler,Spring默认是帮我们启动的,不需要手动启动。
- 使用如下:
private Scheduler scheduler;
spring会自己注入,通过工厂类SchedulerFactoryBean
的getObject()
方法。
搞个基本的增删改查,很简单,代码也没怎么优化,就这样吧。
|
- 和上面得基本demo没什么两样,就是scheduler 并不需要我们去创建了。
- 当部署多个服务时,也不会重复执行。且任务会负载均衡分配。
5、时间演练
Quartz 提供了下一次运行的时间,我们可以通过下一次运行的时间,比对是否符合我们的预期
public class Test { |
每个 Tigger 都有一个Date getFireTimeAfter(Date afterTime)
的方法,返回的就是下一次运行的时间。