|
目录:
1. SpringBoot集成Quartz
2. 实现定时任务逻辑
3. 动态创建定时任务
4. Quartz常用类
5. Quartz任务熄火策略
6. Cron表达式速成
7. Quartz使用技巧之 通过JobDataMap和SchedulerContext传递数据
8. Spring框架Schedule 功能 的使用方法
Quartz是开源组织OpenSymphony的一个作业调度框架,采用多线程架构,可伸缩性强,可集群扩展。SpringBoot集成Quartz简单高效,只需实现Job接口,在方法execute()中添加业务逻辑 。
Spring框架自带了Schedule功能,能满足小型项目对定时任务的功能需求,同样支持Cron表达式、固定间隔、固定频率三种配置方式,但和Quartz相比,不支持任务信息数据库持久化。
| Cron表达式 | 固定间隔 | 固定频率 | 传递数据 | 任务持久化 | Quartz | √ | √ | √ | √ | √ | Spring Schedule | √ | √ | √ | × | × |
本文分享SpringBoot集成和配置Quartz的方法,以及在项目中的实际应用方案,最后介绍Spring 框架自带的Schedule功能的用法。
| 代码文件 | 功能 要点 | SpringBoot集成Quartz | pom.xml | 引入 Quartz 依赖 : spring-boot-starter-quartz | application.yml | 配置Quartz属性,配置Job运行时间cron表达式 | QuartzConfig.java | 配置Bean: JobDetail, Trigger,读取cron运行时间配置 | 实现定时任务 | QuartzJob.java | 实现Job接口,或者继承QuartzJobBean类 | 动态创建任务 | CheckController .java | 增加REST接口/chk/job,创建一个Job定时任务,通过Context上下文传递数据。 |
项目代码: https://github.com/jextop/StarterApi/
示例代码: https://github.com/rickding/HelloJava/tree/master/HelloQuartz
一,SpringBoot集成Quartz
1. 新建SpringBoot项目时,选中Quartz,将自动添加Quartz依赖。
![点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小](png/1581246471106256.png)
2. 已有SpringBoot项目,可以在pom.xml中直接添加Quartz依赖。
<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-quartz </artifactId>
</dependency>
3. 在application.yml中配置Quartz,指定任务存储类型:
memory:内存方式,默认。
jdbc:数据库持久化方式,将创建数据表并保存任务信息。
spring:
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: always
job:
quartz:
cron: 0 0/23 * * *
4. 在QuartzConfig.java中配置Bean,声明JobDetail和Trigger,使用cron表达式设置任务运行时间:
@Configuration
@ConfigurationProperties ( "job.quartz" )
public class QuartzConfig {
private String cron ;
@Bean
public JobDetail quartzJob () {
return JobBuilder. newJob (QuartzJob. class ).storeDurably().build() ;
}
@Bean
public Trigger quartzTrigger () {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder. cronSchedule ( cron ) ;
return TriggerBuilder. newTrigger ()
.forJob(quartzJob())
.withSchedule(scheduleBuilder)
.build() ;
}
public String getCron () {
return cron ;
}
public void setCron (String cron) {
this . cron = cron ;
}
}
二,定时任务QuartzJob.java ,继承QuartzJobBean类 , 实现Job接口。
从JobExecutionContext中读取附加信息,执行业务逻辑。
public class QuartzJob extends QuartzJobBean {
@Override
protected void executeInternal (JobExecutionContext context) throws JobExecutionException {
LogUtil. info ( "quartz job " , new Date()) ;
try {
JextService jextService = (JextService) context.getScheduler().getContext().get( "jextService" ) ;
if (jextService != null ) {
jextService.getInfo( true ) ;
}
} catch (SchedulerException e) {
LogUtil. info (e.getMessage()) ;
}
}
}
三,动态创建定时任务
1. 增加RestController: CheckController.java
2. 增加REST接口/chk/job,创建一个定时任务,添加附加信息到Scheduler上下文中。
@GetMapping ( value = "/chk/job" )
public Object job () {
JobDetail job = JobBuilder. newJob (QuartzJob. class ).build() ;
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder. newTrigger ()
.forJob(job)
.startAt( new Date())
.build() ;
Date date = null;
try {
Scheduler scheduler = StdSchedulerFactory. getDefaultScheduler () ;
scheduler.getContext().put( "jextService" , jextService ) ;
date = scheduler.scheduleJob(job , trigger) ;
scheduler.startDelayed( 1 ) ;
} catch (SchedulerException e) {
e.printStackTrace() ;
}
final Date jobDate = date ;
return new HashMap<String , Object>() {{
put( "chk" , "job" ) ;
put( "date" , jobDate ) ;
}} ;
}
3. Postman调用REST接口创建定时任务示例
四,Quartz常用类
Quartz提供的常用类: Scheduler, SchedulerFactory, Job, JobDetail, JobBuilder, Trigger, TriggerBuilder, ScheduleBuilder,UML类图如下:
![点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小](png/1581309471662910.png)
Scheduler时Quartz调度程序的主要接口, 维护一个JobDetails和Triggers的注册表,到触发时间时,调度程序将执行Job。
调度程序Scheduler实例通过SchedulerFactory工厂创建,有两个实现类DirectSchedulerFactory和StdSchedulerFactory,前者不写入持久化数据库,后者加载quartz.properties属性配置文件,将查找加载当前目录和org.quartz包。
任务是实现Job接口的一个类,实现方法execute(),可声明属性:
- @DisallowConcurrentExecution,同时只执行一个实例。
- @PersisJobDataAfterExecution,正常执行后将JobDataMap备份。
JobDetail将任务属性传递给Scheduler,通过JobBuilder创建,JobDataMap保存任务实例的状态信息。
触发器Trigger通过TriggerBuilder创建,结合ScheduleBuilder设置时间规则,可通过JobDataMap传递数据给Job。常用的两种触发器:
- SimpleTrigger:指定开始时间、结束时间、重复次数、执行间隔。
- CronTrigger:使用Cron表达式设置时间规则。
五,Quartz任务熄火策略
ScheduleBuilder设置时间规则时,可配置Misfire选项,指定执行失败熄火时的处理规则:
| 含义 | 支持ScheduleBuilder | IgnoreMisfires | 马上执行,比如整点9点失败,系统10:15启动,会马上执行9点10点的任务。 | SimpleSchedule
CronScheduleBuilder
CalendarIntervalScheduleBuilder
DailyTimeIntervalScheduleBuilder | FireNow | 立即再次触发 | SimpleSchedule | NowWithExistingCount | 立即再次触发,不计入总次数。 | SimpleSchedule | NowWithRemainingCount | 立即再次触发,计入总次数。 | SimpleSchedule | NextWithExistingCount | 等待下次执行,不计入总次数。 | SimpleSchedule | NextWithRemainingCount | 等待下次执行,计入总次数。 | SimpleSchedule | DoNothing | 不做任何处理,执行下一次周期。 | CronScheduleBuilder
CalendarIntervalScheduleBuilder
DailyTimeIntervalScheduleBuilder | FireAndProceed | 合并下一个周期,正常执行。比如整点9点10点失败,系统10:15启动,在11点合并执行一次。 | CronScheduleBuilder
CalendarIntervalScheduleBuilder
DailyTimeIntervalScheduleBuilder |
六,Cron表达式速成
Cron表达式是一个字符串,定义时间规则,由6或7个时间域组成,空格分隔 1张表整理清楚含义和规则,并举例常用表达式,放手边速查。
时间域序号 | 含义 | 取值范围 | 特殊字符 | 1 | 秒Seconds | 0-59 | ,-*/ | 2 | 分钟Minutes | 0-59 | ,-*/ | 3 | 小时Hours | 0-23 | ,-*/ | 4 | 日期DayOfMonth | 1-31 | ,-*/ L W C | 5 | 月份Month | 1-12 | ,-*/ JAN-DEC | 6 | 星期DayOfWeek | 1-7 | ,-*/ L C # SUN-SAT | 7 | 年Year (可选) | 1970-2099 | ,-*/ | 特殊字符含义 JAN-DEC 月份英语简称
SUN-SAT 星期英语简称
星期的1表示星期天,2表示星期一,依次类推
* 表示取值范围内的所有数字
/ 表示每隔固定时间触发依次,比如0/5表示从0开始每5个单位时间
- 表示两个数字之间的范围,比如3-7表示3到7之间,包含3和7
, 表示离散的枚举数字,比如2,3,5,7表示指定的这几个时间
只能用在日期DayOfMonth和星期DayOfWeek两个域,表示不指定,避免日期和星期的互相影响,比如指定每月的20日,不管是星期几,正确写法是:0 0 0 20 * ,其中星期只能用 ,如果使用* 将触发错误。
L 只能用于日期DayOfMonth和星期DayOfWeek,用于日期时表示月份的最后一天,用于星期时不加数字表示周六,加数字表示最后一个周几,比如0 0 0 * 5L表示每月的最后一个星期四
W 只能用于日期DayOfMonth,表示周一到周五有效工作日,将在离指定日期的最近的有效工作日触发事件。例如在日期使用5W,如果5日是星期六,则将在最近的工作日星期五(4日)触发。如果5日是星期天,则在6日(星期一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近工作日寻找不会跨月份。
LW 两个字符连用时表示某个月最后一个工作日
# 只能用于星期DayOfWeek,表示每个月第几个星期几,比如4#2表示第二个星期三 常用表达式 0/5 * * * * 每5秒钟
0 0/5 * * * 每5分钟
0 0 6 * * 每天早上6点
0 0 9,13,19 * * 每天上午9点,下午1点,晚上7点
0 0 23-7/2,8 * * 每天晚上11点到早上7点之间的每两个小时,和早上8点
0 0/30 9-17 * * 朝九晚五工作时间内每半小时
0 0 9-21 * MON-SAT 表示996每天的每小时
0 0 7 LW * 每月最后一个工作日早上7点
0 0 4 1 1 每年的1月1日早上4点
七,Quartz使用技巧 之通过JobDataMap和SchedulerContext传递数据
在Job.execute()方法中实现业务逻辑时,经常需要一些附加信息。Quartz提供了JobExecutionContext上下文传递数据。
l 通过JobDataMap传递数据
代码下载: https://github.com/rickding/HelloJava/tree/master/HelloQuartz
src/main/java/com/hello/quartz/
├── QuartzConfig.java
├── QuartzJob.java
| 代码文件 | 功能 要点 | 设置数据 | QuartzConfig.java | 创建JobDetail或者Trigger时,调用usingJobData()设置数据 | 读取数据 | QuartzJob.java | 执行任务时,调用 JobExecutionContext.getMergedJobDataMap() 获取数据 |
1,设置数据:JobDetail和Trigger都可以调用usingJobData()方法设置数据。
@Configuration
@ConfigurationProperties ( "quartz" )
public class QuartzConfig {
@Bean
public JobDetail quartzJob () {
JobDataMap dataMap = new JobDataMap() {{
put( "job_str" , "str_test" ) ;
}} ;
return JobBuilder. newJob (QuartzJob. class )
.usingJobData(dataMap)
.storeDurably()
.build() ;
}
@Bean
public Trigger quartzTrigger () {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder. cronSchedule ( cron ) ;
JobDataMap dataMap = new JobDataMap() {{
put( "trigger_int" , 333 ) ;
}} ;
return TriggerBuilder. newTrigger ()
.forJob(quartzJob())
.withSchedule(scheduleBuilder)
.usingJobData(dataMap)
.build() ;
}
}
2,读取数据:从JobExecutionContext中读取JobDataMap获取数据,执行业务逻辑。
public class QuartzJob extends QuartzJobBean {
@Override
protected void executeInternal (JobExecutionContext context) throws JobExecutionException {
// get data from context
JobDataMap dataMap = context.getMergedJobDataMap() ;
for (Map.Entry<String , Object> data : dataMap.entrySet()) {
System. out .printf( "%s = %s
" , data.getKey() , data.getValue()) ;
}
// do work
}
}
3,运行输出:
trigger_int = 333
job_str = str_test
l 通过SchedulerContext传递数据
另一个传递数据的方式是构建Scheduler时为SchedulerContext设置数据。 代码详见上文中第二、第三部分:
代码下载: https://github.com/jextop/StarterApi/
src/main/java/com/starter/
├── controller/CheckController.java
├── job/QuartzJob.java
读取数据方式一样,因为 JobExecutionContext.getMergedJobDataMap()已经将数据合并到一起。也可以通过调用SchedulerContext获取。
八, Spring框架Schedule 功能 的使用方 法
Spring Schedule支持异步执行定时任务,支持Cron表达式、固定间隔、固定频率三种配置方式,能满足小型项目对定时任务的功能需求。示例 代码: https://github.com/rickding/HelloJava/tree/master/HelloQuartz
src/main/java/com/hello/quartz/
├── QuartzApplication.java
├── ScheduledJob.java
| 代码文件 | 功能 要点 | 开启功能 | QuartzApplication.java | SpringApplication增加注解:
@EnableScheduling // 打开Schedule功能
@EnableAsysnc // 异步方式执行定时任务 | 配置任务 | ScheduleJob.java | 声明定时任务,功能注解:
@Async // 异步方式执行,声明在类上面时,作用于类里面包含的任务
@Scheduled // 声明定时任务执行时间 |
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class QuartzApplication {
public static void main (String[] args) {
SpringApplication. run (QuartzApplication. class, args) ;
}
}
1, cron表达式声明定时任务,比如每10秒执行一次:
@Async
@Scheduled ( cron = "0/1 0 * * * * " )
public void scheduledCron () {
System. out .printf( "scheduled cron: %s
" , new Date()) ;
}
2, 固定频率执行定时任务,比如每20秒执行一次:
@Scheduled ( fixedRate = 1000 * 2 0 , initialDelay = 1000 * 2 0 )
public void scheduledRate () {
System. out .printf( "fixedRate: %s
" , new Date()) ;
}
3, 固定间隔执行定时任务,比如每20秒执行一次:
@Scheduled ( fixedDelay = 1000 * 3 0 , initialDelay = 1000 * 3 0 )
public void scheduledDelay () {
System. out .printf( "fixedDelay: %s
" , new Date()) ;
}
注意固定频率和固定间隔两类定时任务,默认在程序启动时就会执行一次,可以通过指定initialDelay参数控制首次执行时间。
scheduled cron: Sun Feb 09 18 : 09 : 19 CST 2020
fixedRate: Sun Feb 09 18 : 09 : 28 CST 2020
scheduled cron: Sun Feb 09 18 : 09 : 38 CST 2020
--------------------------------
![点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小](png/1581246561395204.png)
----------------------------
原文链接:https://blog.51cto.com/13851865/2468550
程序猿的技术大观园:www.javathinker.net
[这个贴子最后由 flybird 在 2020-03-13 12:11:40 重新编辑]
|
|