在我们常见的业务场景难免会遇到需要做定时任务的功能,一般Springboot自带的定时功能可以满足corn表达式不变的定时任务,但是当我们想动态改变corn表达式的时候,就可以用到开源任务调度框架—Quartz。
Springboot2整合Quartz
pom依赖
<!-- 定时任务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
yml配置
spring:
quartz:
#相关属性配置
properties:
org:
quartz:
scheduler:
instanceName: quartzScheduler
instanceId: AUTO
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
最佳实践思路
不采用在数据库生成Quartz的二十几表,那样数据库显得比较臃肿,直接采用Quartz在内存中记录每条定时任务的状态,然后只用创建一张任务表存储任务。在程序每次启动的时候,去读取任务表,加载到调度器上面即可。
任务表
-- flowable.quartz_job definition
CREATE TABLE `quartz_job` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
`job_name` varchar(50) NOT NULL COMMENT '任务名称',
`job_group` varchar(50) NOT NULL COMMENT '任务组别',
`job_class_name` varchar(100) NOT NULL COMMENT '任务目标执行class',
`cron_expression` varchar(100) NOT NULL COMMENT 'cron表达式',
`trigger_state` varchar(15) NOT NULL COMMENT '触发器状态',
`old_job_name` varchar(50) NOT NULL COMMENT '旧的名称',
`old_job_group` varchar(50) NOT NULL COMMENT '旧的组别',
`description` varchar(100) NOT NULL COMMENT '描述',
PRIMARY KEY (`id`),
UNIQUE KEY `un_group_name` (`job_group`,`job_name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='任务表';
使用调度器API
package org.tegic.spring.activity.service.impl;
import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.tegic.spring.activity.common.Result;
import org.tegic.spring.activity.dao.JobMapper;
import org.tegic.spring.activity.entity.QuartzJob;
import org.tegic.spring.activity.enums.JobStatus;
import org.tegic.spring.activity.service.IJobService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@Service
public class JobServiceImpl implements IJobService {
private static final String TRIGGER_IDENTITY = "trigger";
@Autowired
private Scheduler scheduler;
@Autowired
private JobMapper jobMapper;
@Override
public PageInfo<QuartzJob> listQuartzJob(String jobName, Integer pageNo, Integer pageSize) {
PageHelper.startPage(pageNo, pageSize);
List<QuartzJob> jobList = jobMapper.listJob(jobName);
PageInfo<QuartzJob> pageInfo = new PageInfo<QuartzJob>(jobList);
return pageInfo;
}
// 保存任务
@Override
public Result saveJob(QuartzJob quartz) {
try {
schedulerJob(quartz);
quartz.setTriggerState(JobStatus.RUNNING.getStatus());
quartz.setOldJobGroup(quartz.getJobGroup());
quartz.setOldJobName(quartz.getJobName());
jobMapper.saveJob(quartz);
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
return Result.ok();
}
// 触发任务,只执行一次
@Override
public Result triggerJob(String jobName, String jobGroup) {
JobKey key = new JobKey(jobName, jobGroup);
try {
scheduler.triggerJob(key);
} catch (SchedulerException e) {
e.printStackTrace();
return Result.error();
}
return Result.ok();
}
// 暂停任务
@Override
public Result pauseJob(String jobName, String jobGroup) {
JobKey key = new JobKey(jobName, jobGroup);
try {
scheduler.pauseJob(key);
jobMapper.updateJobStatus(jobName, jobGroup, JobStatus.PAUSED.getStatus());
} catch (SchedulerException e) {
e.printStackTrace();
return Result.error();
}
return Result.ok();
}
// 恢复任务
@Override
public Result resumeJob(String jobName, String jobGroup) {
JobKey key = new JobKey(jobName, jobGroup);
try {
scheduler.resumeJob(key);
jobMapper.updateJobStatus(jobName, jobGroup, JobStatus.RUNNING.getStatus());
} catch (SchedulerException e) {
e.printStackTrace();
return Result.error();
}
return Result.ok();
}
// 删掉任务
@Override
public Result removeJob(String jobName, String jobGroup) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(TRIGGER_IDENTITY + jobName, jobGroup);
scheduler.pauseTrigger(triggerKey); // 停止触发器
scheduler.unscheduleJob(triggerKey); // 移除触发器
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup)); // 删除任务
jobMapper.removeQuartzJob(jobName, jobGroup);
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
return Result.ok();
}
// 获取任务
@Override
public QuartzJob getJob(String jobName, String jobGroup) {
return jobMapper.getJob(jobName, jobGroup);
}
// 更新任务
@Override
public Result updateJob(QuartzJob quartz) {
try {
scheduler.deleteJob(new JobKey(quartz.getOldJobName(), quartz.getOldJobGroup()));
schedulerJob(quartz);
quartz.setOldJobGroup(quartz.getJobGroup());
quartz.setOldJobName(quartz.getJobName());
jobMapper.updateJob(quartz);
} catch (Exception e) {
e.printStackTrace();
return Result.error();
}
return Result.ok();
}
// 将任务绑定到调度器上
@Override
public void schedulerJob(QuartzJob job) throws Exception {
// 构建job信息
Class cls = Class.forName(job.getJobClassName());
// cls.newInstance(); // 检验类是否存在
JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(job.getJobName(), job.getJobGroup())
.withDescription(job.getDescription()).build();
// 触发时间点
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression().trim());
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(TRIGGER_IDENTITY + job.getJobName(), job.getJobGroup()).startNow()
.withSchedule(cronScheduleBuilder).build();
// 交由Scheduler安排触发
scheduler.scheduleJob(jobDetail, trigger);
}
}
实现CommandLineRunner类,重写run方法,启动的时候就去加载定时任务。
private void loadJobToQuartz() throws Exception {
List<QuartzJob> jobs = jobMapper.listJob("");
for (QuartzJob job : jobs) {
jobService.schedulerJob(job);
if (JobStatus.PAUSED.getStatus().equals(job.getTriggerState())) {
scheduler.pauseJob(new JobKey(job.getJobName(), job.getJobGroup()));
}
}
}
到此配置基本完毕。