Quartz 存储任务信息有两种方式,使用内存或者使用数据库来存储,这里我们采用 MySQL 数据库存储的方式,首先需要新建 Quartz 的相关表,sql 脚本下载地址:http://www.quartz-scheduler.org/downloads/,名称为 tables_mysql.sql,创建成功后数据库中多出 11 张表
org.springframework.boot spring-boot-starter-quartz
# 定时任务配置
sprinng:quartz:#数据库方式job-store-type: jdbc# quartz 相关属性配置properties:org:quartz:scheduler:instanceName: examSchedulerinstanceId: AUTOjobStore:class: org.quartz.impl.jdbcjobstore.JobStoreTXdriverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegatetablePrefix: QRTZ_isClustered: trueclusterCheckinInterval: 10000useProperties: falsethreadPool:class: org.quartz.simpl.SimpleThreadPoolthreadCount: 10threadPriority: 5threadsInheritContextClassLoaderOfInitializingThread: true
/*** Quartz定时任务核心的功能实现类*/private Scheduler scheduler;/*** 注入* @param schedulerFactoryBean*/public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) {scheduler = schedulerFactoryBean.getScheduler();}
/*** 任务业务类,用于动态处理任务信息* @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);
}
@Service
public class JobServiceImpl implements JobService {/*** Quartz定时任务核心的功能实现类*/private Scheduler scheduler;/*** 注入* @param schedulerFactoryBean*/public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) {scheduler = schedulerFactoryBean.getScheduler();}@Overridepublic 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表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();scheduler.scheduleJob(jobDetail, trigger);} catch (Exception e) {e.printStackTrace();}}@Overridepublic 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);}@Overridepublic void pauseJob(String jobName, String jobGroup) {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);scheduler.pauseTrigger(triggerKey);log.info("++++++++++暂停任务:{}", jobName);} catch (SchedulerException e) {e.printStackTrace();}}@Overridepublic void resumeJob(String jobName, String jobGroup) {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);scheduler.resumeTrigger(triggerKey);log.info("++++++++++重启任务:{}", jobName);} catch (SchedulerException e) {e.printStackTrace();}}@Overridepublic void deleteJob(String jobName, String jobGroup) {try {JobKey jobKey = JobKey.jobKey(jobName,jobGroup);scheduler.deleteJob(jobKey);log.info("++++++++++删除任务:{}", jobKey);} catch (SchedulerException e) {e.printStackTrace();}}
}
我们自己如果需要执行一个定时方法需要实现Job接口,重写execute方法,例子如下:
我们可以写多个这种类,供我们执行不同的定时操作任务!
@Component
public class AddBookJob implements Job {@Autowiredprivate PaperQuService paperQuService;@Autowiredprivate UserBookService userBookService;@Overridepublic 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为考试IDPaperDTO dto = JSON.parseObject(data, PaperDTO.class);// 错题列表List ids = paperQuService.listWrongIds(dto.getId());for (String id : ids) {//加入错题本userBookService.addBook(dto.getUserId(), dto.getExamId(), id);}}
}
业务中调用时使用注入的上文中接口类jobService,调用addCroJob方法实现方.
jobService.addCronJob(AddBookJob.class, bookName, JobGroup.SYSTEM, JSON.toJSONString(dto)); //业务中调用@Overridepublic 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中)}
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;}
}