本文主要介绍使用SpringBoot的起步依赖和融入SpringBoot数据库连接的yml配置。
添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
配置文件
配置可以直接加到 application.yml
进行自动装配,数据源会自动使用当前项目的数据源配置或者连接池配置。
具体的配置含义可以参照: https://www.w3cschool.cn/quartz_doc/quartz_doc-ml8e2d9m.html
配置值对应 spring.quartz.properties 后面的那些
spring:
quartz:
# 相关属性配置
properties:
org:
quartz:
scheduler:
instanceName: clusteredScheduler
instanceId: AUTO
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_
isClustered: true
clusterCheckinInterval: 10000
useProperties: false
# 线程池的参数配置
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: false
# 指定监听器的类 进行属性装配,这里我添加了一个监听器的装配类
plugin:
runningListener:
class: com.demo.core.job.plugin.RunningListenerPlugin
# 自定义属性,代码中读取,用于控制是否开启监听
enableRunningLog: true
# 持久化-数据库方式存储
job-store-type: jdbc
数据库建表
使用的是2.2.3版本的 Oracle 建表语句:建表SQL文件
如果使用别的数据库,可以到GitHub上直接获取:https://github.com/quartz-scheduler/quartz
鉴于很多人不太会找,我简单说下建表语句的查找方法:
- 进入GitHub仓库之后,切换至Tag,找到你对应的版本;
- 进入切换到tag之后,点击Find file按钮, 搜索 .sql,根据文件名大概就能判断哪个是符合你需求的建表语句;
- 或者你知道文件的路径,可以直接找,例如:2.1.x版本的建表语句一般放在 docs/dbTables 下面,根据里面的SQL文件名就能找到你要的建表语句;
配置完启动就可以使用的了。
实际应用代码
创建定时任务的可选参数,我们以简单任务和CRON任务为例,以下DTO字段主要源于 QRTZ_TRIGGERS
、QRTZ_CRON_TRIGGERS
和 QRTZ_SIMPLE_TRIGGERS
这三张表。 根据表结构不难看出,触发器的基本属性在 QRTZ_TRIGGERS
中,另外两张表保存了不同类型触发器的特有参数。
TriggerDto.java 对应 QRTZ_TRIGGERS
@Getter
@Setter
public class TriggerDto {
/**
* 调度器名称
*/
private String schedName;
/**
* 触发器名称
*/
private String triggerName;
/**
* 触发器分组
*/
private String triggerGroup;
/**
* Job名称
*/
private String jobName;
/**
* Job分组
*/
private String jobGroup;
/**
* Job描述
*/
private String description;
/**
* 下次执行时间 毫秒级时间戳
*/
private Long nextFireTime;
/**
* 上次执行时间 毫秒级时间戳
*/
private Long prevFireTime;
/**
* 优先级
*/
private Integer priority;
/**
* 触发器状态
*/
private String triggerState;
/**
* 触发器类型
*/
@NotEmpty
private String triggerType;
/**
* 开始时间 毫秒级时间戳
*/
private Long startTime;
/**
* 结束时间 毫秒级时间戳
*/
private Long endTime;
private String calendarName;
private Integer misfireInstr;
}
TriggerCreateParam.java 包含CRON和SIMPLE任务的参数
@Getter
@Setter
public class TriggerCreateParam extends TriggerDto {
/**
* 实际执行任务类名
*/
@NotEmpty
private String jobClassName;
/**
* CRON表达式 针对CRON任务
*/
private String cronExpression;
/**
* 开始时间
*/
private Date start;
/**
* 结束时间
*/
private Date end;
/**
* 重复次数 针对简单任务 0表示无限次数
*/
private Integer repeatCount;
/**
* 重复时间间隔 针对简单任务
*/
private Integer repeatInterval;
private List<JobData> jobDataList;
}
通用的创建方法
/**
* 创建一个定时任务(触发器)
*
* @param triggerCreateParam 创建参数
* @throws SchedulerException 任务调度异常
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public void createTrigger(TriggerCreateParam triggerCreateParam) throws SchedulerException {
String jobClassName = triggerCreateParam.getJobClassName();
Class forName;
try {
forName = Class.forName(jobClassName);
if (!org.quartz.Job.class.isAssignableFrom(Class.forName(jobClassName))) {
throw new IllegalArgumentException("任务类需要继承 org.quartz.Job");
}
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("任务类名不存在, 请先正确创建该执行类" + jobClassName);
}
JobBuilder jobBuilder = JobBuilder.newJob(forName)
.withIdentity(triggerCreateParam.getJobName(), triggerCreateParam.getJobGroup())
.withDescription(triggerCreateParam.getDescription());
// 检查是否有额外的任务参数,并设置Job Data
if (CollectionUtils.isNotEmpty(triggerCreateParam.getJobDataList())) {
JobDataMap data = new JobDataMap();
List<JobData> jobDataList = triggerCreateParam.getJobDataList();
for (JobData jobData : jobDataList) {
data.put(jobData.getName(), jobData.getValue());
}
jobBuilder = jobBuilder.usingJobData(data);
}
JobDetail jobDetail = jobBuilder.build();
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger()
.withIdentity(triggerCreateParam.getTriggerName(), triggerCreateParam.getTriggerGroup()).forJob(jobDetail);
if (triggerCreateParam.getStartTime() != null && triggerCreateParam.getStartTime() > 0) {
triggerBuilder.startAt(new Date(triggerCreateParam.getStartTime()));
}
if (triggerCreateParam.getEndTime() != null && triggerCreateParam.getEndTime() > 0) {
triggerBuilder.endAt(new Date(triggerCreateParam.getEndTime()));
}
ScheduleBuilder scheduleBuilder;
// 根据不同的类型,设置不同参数,构建对应类型的触发器
if ("CRON".equalsIgnoreCase(triggerCreateParam.getTriggerType())) {
if (StringUtils.isEmpty(triggerCreateParam.getCronExpression())) {
throw new IllegalArgumentException("CRON任务中,CRON表达式不能为空");
}
scheduleBuilder = CronScheduleBuilder.cronSchedule(triggerCreateParam.getCronExpression());
} else if ("SIMPLE".equalsIgnoreCase(triggerCreateParam.getTriggerType())) {
if (triggerCreateParam.getRepeatInterval() == null) {
throw new IllegalArgumentException("简单任务中,重复间隔不能为空");
}
if (triggerCreateParam.getRepeatCount() == null) {
throw new IllegalArgumentException("简单任务中,重复次数不能为空");
}
int interval = triggerCreateParam.getRepeatInterval();
int count = triggerCreateParam.getRepeatCount();
if (count < 1) {
scheduleBuilder = SimpleScheduleBuilder.repeatSecondlyForever(interval);
} else {
scheduleBuilder = SimpleScheduleBuilder.repeatSecondlyForTotalCount(count, interval);
}
} else {
throw new IllegalArgumentException("不支持的触发器类型:" + triggerCreateParam.getTriggerType());
}
Trigger trigger = triggerBuilder.withSchedule(scheduleBuilder).build();
quartzScheduler.scheduleJob(jobDetail, trigger);
}
从上面的创建方法,我们可以看到有个类名的检查。Quartz的任务实际执行的逻辑代码,都要继承 org.quartz.Job, 实现execute方法,该方法就是定时任务触发时,实际执行的代码。下面是一个简单的定时任务执行类:
@Component
public class DemoJob extends Job {
private static final Logger logger = LoggerFactory.getLogger(DemoJob.class);
@Override
public void safeExecute(JobExecutionContext context) {
// 通过该方法,可以获取到任务定义时传入的参数,实际对应 QRTZ_TRIGGERS.JOB_DATA
context.getJobDetail().getJobDataMap();
logger.info("-----------------测试Quartz任务--------------------");
// 设置执行结果
context.setResult("咕咕咕咕");
}
}
创建一个简单任务
TriggerCreateParam createParam = new TriggerCreateParam();
createParam.setJobName("TEST");
createParam.setJobGroup("TEST");
createParam.setTriggerGroup("TEST");
createParam.setTriggerName("TEST");
createParam.setDescription("咕咕咕");
createParam.setTriggerType("SIMPLE");
createParam.setRepeatInterval(10);
createParam.setRepeatCount(5);
myQuartzService.createTrigger(createParam);
执行日志
2020-06-04 18:11:42.344 INFO 16452 --- [eduler_Worker-1] com.demo.core.job.example.DemoJob : -----------------测试Quartz任务--------------------
2020-06-04 18:11:42.344 INFO 16452 --- [eduler_Worker-1] c.n.c.job.listener.JobRunningListener : Job DemoJobTest.DemoJobTest execution complete at 18:11:42 06/04/2020 and reports: 咕咕咕咕
2020-06-04 18:11:52.336 INFO 16452 --- [eduler_Worker-2] c.n.c.job.listener.JobRunningListener : Job DemoJobTest.DemoJobTest fired (by trigger DemoJobTest.DemoJobTest_trigger) at: 18:11:52 06/04/2020
2020-06-04 18:11:52.336 INFO 16452 --- [eduler_Worker-2] com.demo.core.job.example.DemoJob : -----------------测试Quartz任务--------------------
2020-06-04 18:11:52.336 INFO 16452 --- [eduler_Worker-2] c.n.c.job.listener.JobRunningListener : Job DemoJobTest.DemoJobTest execution complete at 18:11:52 06/04/2020 and reports: 咕咕咕咕
2020-06-04 18:12:02.333 INFO 16452 --- [eduler_Worker-3] c.n.c.job.listener.JobRunningListener : Job DemoJobTest.DemoJobTest fired (by trigger DemoJobTest.DemoJobTest_trigger) at: 18:12:02 06/04/2020
2020-06-04 18:12:02.333 INFO 16452 --- [eduler_Worker-3] com.demo.core.job.example.DemoJob : -----------------测试Quartz任务--------------------
2020-06-04 18:12:02.333 INFO 16452 --- [eduler_Worker-3] c.n.c.job.listener.JobRunningListener : Job DemoJobTest.DemoJobTest execution complete at 18:12:02 06/04/2020 and reports: 咕咕咕咕
2020-06-04 18:12:12.334 INFO 16452 --- [eduler_Worker-4] c.n.c.job.listener.JobRunningListener : Job DemoJobTest.DemoJobTest fired (by trigger DemoJobTest.DemoJobTest_trigger) at: 18:12:12 06/04/2020
2020-06-04 18:12:12.334 INFO 16452 --- [eduler_Worker-4] com.demo.core.job.example.DemoJob : -----------------测试Quartz任务--------------------
2020-06-04 18:12:12.334 INFO 16452 --- [eduler_Worker-4] c.n.c.job.listener.JobRunningListener : Job DemoJobTest.DemoJobTest execution complete at 18:12:12 06/04/2020 and reports: 咕咕咕咕