一、Quartz简介
Quartz是一个开源作业调度框架,其核心概念包括:
- Job:表示一个工作,要执行的具体内容。
- JobDetail:表示一个具体的可执行的调度程序,包含任务调度的方案和策略。
- Trigger:表示一个调度参数的配置,表示什么时候去调度。
- Scheduler:表示一个调度容器,当JobDetail和Trigger组合时方可进行调度。
- JobDataMap:JobDataMap中可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据(JobDetail & Trigger)。在Job执行时,JobExecutionContext中的JobDataMap是JobDetail中的JobDataMap和Trigger中的JobDataMap的并集,但是如果存在相同的数据,则后者会覆盖前者的值。
//JobDataMap使用
.usingJobData("name", "luffy")
.usingJobData("age", 18)
/**
* 获取JobDetail和Trigger创建时的JobDataMap
*/
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
@DisallowConcurrentExecution:将该注解加到job类上,告诉Quartz不要并发地执行同一个job定义(这里指特定的job类)的多个实例。(针对JobDetail)
@PersistJobDataAfterExecution:将该注解加在job类上,告诉Quartz在成功执行了job类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据。(针对JobDetail)
Job.execute()方法中仅允许抛出一种类型的异常(包括RuntimeExceptions),即JobExecutionException。因此,你应该将execute方法中的所有内容都放到一个”try-catch"块中。job可以使用该异常告诉scheduler,你希望如何来处理发生的异常。
SimpleTrigger:在具体的时间点执行一次,或者在具体的时间点执行,并且以指定的间隔重复执行若干次。
CronTrigger:使用Cron Expressions指定触发策略。
TriggerListeners、JobListeners、SchedulerListeners查看对应接口。
Job Stores:切勿在代码中直接使用JobStore实例。
二、Spring Boot整合Quartz
本文完整示例代码见:
引入maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
Quartz相关配置参考:
自定义Job类实现execute方法,获取JobDetail和Trigger的dataMap属性。
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class LuffyJob implements MyJob {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
/**
* 获取JobDetail和Trigger创建时的JobDataMap
*/
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
logger.info("执行定时任务!");
jobDataMap.forEach((k, v) -> logger.info(k + ":" + v));
mergedJobDataMap.forEach((k, v) -> logger.info(k + ":" + v));
}
}
控制层传入Job和Trigger参数,开启调度器,创建JobDetai和Trigger。
@PostMapping(value = "/startJob")
public String startJob(@RequestBody StartJobDto dto) {
String resInfo = null;
Map<String,String> infoMap = new HashMap<>();
infoMap.put("creator","luffy");
JobDataMap dataMap = new JobDataMap(infoMap);
try {
//开启调度器
scheduler.start();
//创建JobDetail
JobDetail jobDetail = JobBuilder.newJob(getClass(dto.getJobClassName()).getClass())
.withIdentity(dto.getJobName(), dto.getJobGroupName())
.requestRecovery(true)
.usingJobData("name","jobdetal")
.usingJobData("age",2)
.requestRecovery()
.build();
//创建CronScheduleBuilder
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(dto.getCronExpression().trim());
//创建触发器
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger:"+dto.getJobName(), dto.getJobGroupName())
.startNow()
.usingJobData("name","trigger")
.usingJobData("date",new Date().toString())
.withSchedule(scheduleBuilder)
.endAt(DateFormat.getDateTimeInstance().parse("2020-11-13 23:59:59"))
.modifiedByCalendar("Holidays")
.build();
//调度器关联Job和Trigger
HolidayCalendar cal = new HolidayCalendar();
cal.addExcludedDate( DateFormat.getDateTimeInstance().parse("2020-11-13 23:59:59"));
scheduler.addCalendar("Holidays",cal,false,false);
scheduler.scheduleJob(jobDetail,trigger);
resInfo = "success";
} catch (Exception e) {
resInfo = "error";
}
return resInfo;
}
参考链接一:SpringBootQuartz
参考链接二:Quartz 教程
参考链接三:Java任务调度框架Quartz教程
参考链接四:Cron表达式在线
三、异常、中断处理
3.1 异常处理
立即重新执行任务:
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class LuffyJob implements MyJob {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
//do something
} catch (Exception e) {
JobExecutionException exception = new JobExecutionException(e);
/**
* 工作立即重新开始
*/
exception.setRefireImmediately(true);
throw exception;
}
}
}
立即停止所有相关这个任务的触发器:
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class LuffyJob implements MyJob {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
//do something
} catch (Exception e) {
JobExecutionException exception = new JobExecutionException(e);
/**
* 自动取消与此作业关联的所有触发器计划
*/
exception.setUnscheduleAllTriggers(true);
throw exception;
}
}
}
3.2 中断处理
实现InterruptableJob接口,重写execute和interrupt方法即可。
四、测试
前端传入Job类路径、jobName、jobGroupName和cronExpression。
图4-1 Quartz请求测试.png每10秒打印一次dataMap信息,打印结果如下所示:
图4-2 Quartz输出结果信息.png
网友评论