Quartz定时任务项目中应用
一.数据库表准备
Quartz 存储任务信息有两种方式,使用内存或者使用数据库来存储,这里我们采用 MySQL 数据库存储的方式,首先需要新建 Quartz 的相关表,sql 脚本下载地址:http://www.quartz-scheduler.org/downloads/,名称为 tables_mysql.sql,创建成功后数据库中多出 11 张表
二.依赖导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
三.application.yml配置
# 定时任务配置
sprinng:
quartz:
#数据库方式
job-store-type: jdbc
# quartz 相关属性配置
properties:
org:
quartz:
scheduler:
instanceName: examScheduler
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: true
四.自定义实现类实现自定义接口
4.1 引入Scheduler
/**
* Quartz定时任务核心的功能实现类
*/
private Scheduler scheduler;
/**
* 注入
* @param schedulerFactoryBean
*/
public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) {
scheduler = schedulerFactoryBean.getScheduler();
}
4.2定义接口JobService
/**
* 任务业务类,用于动态处理任务信息
* @author bool
* @date 2020/11/29 下午2:17
*/
public interface JobService {
/**
* 任务数据
*/
String TASK_DATA = "taskData";
/**
* 添加定时任务
* @param jobClass
* @param jobName
* @param jobGroup
* @param cron
* @param data
*/
void addCronJob(Class jobClass, String jobName, String jobGroup, String cron, String data);
/**
* 添加立即执行的任务
* @param jobClass
* @param jobName
* @param jobGroup
* @param data
*/
void addCronJob(Class jobClass, String jobName, String jobGroup, String data);
/**
* 暂停任务
* @param jobName
* @param jobGroup
*/
void pauseJob(String jobName, String jobGroup);
/**
* 恢复任务
* @param triggerName
* @param triggerGroup
*/
void resumeJob(String triggerName, String triggerGroup);
/**
* 删除job
* @param jobName
* @param jobGroup
*/
void deleteJob(String jobName, String jobGroup);
}
4.3定义实现类JobServiceImpl
@Service
public class JobServiceImpl implements JobService {
/**
* Quartz定时任务核心的功能实现类
*/
private Scheduler scheduler;
/**
* 注入
* @param schedulerFactoryBean
*/
public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) {
scheduler = schedulerFactoryBean.getScheduler();
}
@Override
public void addCronJob(Class jobClass, String jobName, String jobGroup, String cron, String data) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail != null) {
log.info("++++++++++任务:{} 已存在", jobName);
this.deleteJob(jobName, jobGroup);
}
log.info("++++++++++构建任务:{},{},{},{},{} ", jobClass.toString(), jobName, jobGroup, cron, data);
//构建job信息
jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build();
//用JopDataMap来传递数据
jobDetail.getJobDataMap().put(TASK_DATA, data);
//表达式调度构建器(即任务执行的时间,每5秒执行一次)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void addCronJob(Class jobClass, String jobName, String jobGroup, String data) {
// 随机3-8秒后执行
java.util.Calendar cl = java.util.Calendar.getInstance();
cl.setTimeInMillis(System.currentTimeMillis());
cl.add(Calendar.SECOND, 3 + new Random().nextInt(5));
this.addCronJob(jobClass, jobName, jobGroup, CronUtils.dateToCron(cl.getTime()), data);
}
@Override
public void pauseJob(String jobName, String jobGroup) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
scheduler.pauseTrigger(triggerKey);
log.info("++++++++++暂停任务:{}", jobName);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@Override
public void resumeJob(String jobName, String jobGroup) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
scheduler.resumeTrigger(triggerKey);
log.info("++++++++++重启任务:{}", jobName);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
@Override
public void deleteJob(String jobName, String jobGroup) {
try {
JobKey jobKey = JobKey.jobKey(jobName,jobGroup);
scheduler.deleteJob(jobKey);
log.info("++++++++++删除任务:{}", jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
4.4 业务需要执行的定时方法
我们自己如果需要执行一个定时方法需要实现Job接口,重写execute方法,例子如下:
我们可以写多个这种类,供我们执行不同的定时操作任务!
@Component
public class AddBookJob implements Job {
@Autowired
private PaperQuService paperQuService;
@Autowired
private UserBookService userBookService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDetail detail = jobExecutionContext.getJobDetail();
String name = detail.getKey().getName();
String group = detail.getKey().getGroup();
String data = String.valueOf(detail.getJobDataMap().get(JobService.TASK_DATA));
log.info("++++++++++定时任务:考完加入错题本");
log.info("++++++++++jobName:{}", name);
log.info("++++++++++jobGroup:{}", group);
log.info("++++++++++taskData:{}", data);
// 转换数据,id为试卷id,examId为考试ID
PaperDTO dto = JSON.parseObject(data, PaperDTO.class);
// 错题列表
List<String> ids = paperQuService.listWrongIds(dto.getId());
for (String id : ids) {
//加入错题本
userBookService.addBook(dto.getUserId(), dto.getExamId(), id);
}
}
}
addCronJob 函数参数解释
业务中调用时使用注入的上文中接口类jobService,调用addCroJob方法实现方.
jobService.addCronJob(AddBookJob.class, bookName, JobGroup.SYSTEM, JSON.toJSONString(dto)); //业务中调用
@Override
public void addCronJob(Class jobClass, String jobName, String jobGroup, String cron, String data) {
//参数解释
//1.jobClass 就是我们自己定义的需要定时执行的类
//2.jobName 自定义的该任务的Key
//3.jobGroup 自定义的分组
//4.cron 就是Cron表达式,通常使用下述Cron工具类直接调用
//5.data 是在业务中需要传到我们自己定义的需要执行的类中的数据(上文中会将该数据存储在表示execute方法中的jobExecutionContext中)
}
CronUtils 工具类
public class CronUtils {
/**
* 格式化数据
*/
private static final String DATE_FORMAT = "ss mm HH dd MM ? yyyy";
/**
* 准确的时间点到表达式
* @param date
* @return
*/
public static String dateToCron(final Date date){
SimpleDateFormat fmt = new SimpleDateFormat(DATE_FORMAT);
String formatTimeStr = "";
if (date != null) {
formatTimeStr = fmt.format(date);
}
return formatTimeStr;
}
}