Quartz定时任务封装
前言
定时任务对于java开发人员来说比较常用,但是看网上说的都是含含糊糊,有也不是我想要的,还是自己写一个,比较实在。
一、Quartz是什么?
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。
简单说:就是对Spring自带的定时任务Scheduled又进行了一次封装,变得更完善了,更好的适用于业务得场景
开发文档URL:Quartz定时任务开发文档
二、Quartz能做什么?
常见开发场景:
- 每个月15号定时还花呗,借呗。
- 每年女朋友生日定时发送一条祝福短信。
- 每隔一个小时,提醒自己出去走走,提醒自己少脱发。
- 创建支付订单,用户xx小时未进行支付,修改订单状态为超时时间。
- 创建拍卖活动,到固定时间,修改活动状态为开启或者关闭。
简单说:
1.有规律的重复做某事 :
- (一)每年/每月/每日/做某事
- (二)间隔多少 时/分/秒做某事
2.指定某一时刻做某事
- (一)2020年10月10日 10点10分10秒 给喜欢的人发一条短信
三、Quartz怎么使用?
1.引入依赖
代码如下(示例):
<!--定时任务依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
2.配置application.yml
自行修改相关配置(需要下载定时任务11张相关数据表,网上随便搜就能下载):
下载地址:定时任务十一个常用数据库表
#定时任务持久化设置
spring:
quartz:
#相关属性配置
properties:
org:
quartz:
scheduler:
instanceName: clusteredScheduler #调度器实例名称
instanceId: AUTO #调度器实例编号自动生成
jobStore: #持久化方式配置
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #持久化方式配置数据驱动,MySQL数据库
tablePrefix: QRTZ_ #quartz相关数据表前缀名
isClustered: false #开启分布式部署
clusterCheckinInterval: 10000 #分布式节点有效性检查时间间隔,单位:毫秒
useProperties: false #配置是否使用
threadPool:
class: org.quartz.simpl.SimpleThreadPool #线程池实现类
threadCount: 10 #执行最大并发线程数量
threadPriority: 5 #线程优先级
threadsInheritContextClassLoaderOfInitializingThread: true #配置是否启动自动加载数据库内的定时任务,默认true
#数据库方式
job-store-type: jdbc
2.封装定时任务工具类
package com.ruoyi.common.utils.quartz;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @program: moonShine
* @description: 定时任务管理工具类
* @author: Sun
* @create: 2020-03-05 13:37
**/
@Component
public class QuartzManagerUtil {
//设置日期格式
private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 获取当前系统时间
*/
public String getCurrentDate(){
return format.format(new Date());
}
/**
* 将String时间转化为系统Date 时间
* @param time
* @return
*/
public Date toDateTime(String time){
Date date= new Date();
try {
date= format.parse(time);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/**
* 比较两个时间的大小
* date1小于date2返回-1,date1大于date2返回1,相等返回0
* @param date1
* @param date2
* @return
*/
public Integer compareToTime1AndTime2 (String date1,String date2){
Date time1= toDateTime(date1);
Date time2= toDateTime(date2);
return time1.compareTo(time2);
}
@Autowired
private Scheduler scheduler;
@PostConstruct
public void startScheduler() {
try {
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
*
* 方法名称:添加一个定时任务在 指定时间执行一次
*
* 功能描述:
* 〈〉
*
* @param jobClass 任务实现类
* @param jobName 任务名称
* @param jobGroupName 任务组名
* @param jobStartTime 任务执行的时间
* @param jobData 传递数据 参数
* @return : void
* @author : Sun
* @date : 2020/3/4
*/
public void addJobAtTime(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, Date jobStartTime, Map jobData) {
try {
// 任务名称和组构成任务key
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)
.build();
// 设置job参数
if(jobData!= null && jobData.size()>0){
jobDetail.getJobDataMap().putAll(jobData);
}
// 使用simpleTrigger规则
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.startAt(jobStartTime)
.build();
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 增加一个job
*
* @param jobClass
* 任务实现类
* @param jobName
* 任务名称
* @param jobGroupName
* 任务组名
* @param jobTime
* 时间表达式 (这是每隔多少秒为一次任务)
* @param jobTimes
* 运行的次数 (<0:表示不限次数)
* @param jobData
* 参数
*/
public void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, int jobTime,
int jobTimes, Map jobData) {
try {
// 任务名称和组构成任务key
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)
.build();
// 设置job参数
if(jobData!= null && jobData.size()>0){
jobDetail.getJobDataMap().putAll(jobData);
}
// 使用simpleTrigger规则
Trigger trigger = null;
if (jobTimes < 0) {
trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime))
.startNow().build();
} else {
trigger = TriggerBuilder
.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(SimpleScheduleBuilder
.repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes))
.startNow().build();
}
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 增加一个job
*
* @param jobClass
* 任务实现类
* @param jobName
* 任务名称(建议唯一)
* @param jobGroupName
* 任务组名
* @param jobTime
* 时间表达式 (如:0/5 * * * * ? )
* @param jobData
* 参数
*/
public void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, String jobTime, Map jobData) {
try {
// 创建jobDetail实例,绑定Job实现类
// 指明job的名称,所在组的名称,以及绑定job类
// 任务名称和组构成任务key
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)
.build();
// 设置job参数
if(jobData!= null && jobData.size()>0){
jobDetail.getJobDataMap().putAll(jobData);
}
// 定义调度触发规则
// 使用cornTrigger规则
// 触发器key
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.startAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.SECOND))
.withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).startNow().build();
// 把作业和触发器注册到任务调度中
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 修改 一个job的 时间表达式
*
* @param jobName
* @param jobGroupName
* @param jobTime
*/
public void updateJob(String jobName, String jobGroupName, String jobTime) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();
// 重启触发器
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 删除任务一个job
*
* @param jobName
* 任务名称
* @param jobGroupName
* 任务组名
*/
public void deleteJob(String jobName, String jobGroupName) {
try {
scheduler.deleteJob(new JobKey(jobName, jobGroupName));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 暂停一个job
*
* @param jobName
* @param jobGroupName
*/
public void pauseJob(String jobName, String jobGroupName) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 恢复一个job
*
* @param jobName
* @param jobGroupName
*/
public void resumeJob(String jobName, String jobGroupName) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 立即执行一个job
*
* @param jobName
* @param jobGroupName
*/
public void runAJobNow(String jobName, String jobGroupName) {
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
scheduler.triggerJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 获取所有计划中的任务列表
*
* @return
*/
public List<Map<String, Object>> queryAllJob() {
List<Map<String, Object>> jobList = null;
try {
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
jobList = new ArrayList<Map<String, Object>>();
for (JobKey jobKey : jobKeys) {
List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
Map<String, Object> map = new HashMap<>();
map.put("jobName", jobKey.getName());
map.put("jobGroupName", jobKey.getGroup());
map.put("description", "触发器:" + trigger.getKey());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
map.put("jobStatus", triggerState.name());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
map.put("jobTime", cronExpression);
}
jobList.add(map);
}
}
} catch (SchedulerException e) {
e.printStackTrace();
}
return jobList;
}
/**
* 获取所有正在运行的job
* @return
*/
public List<Map<String, Object>> queryRunJob() {
List<Map<String, Object>> jobList = null;
try {
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
jobList = new ArrayList<Map<String, Object>>(executingJobs.size());
for (JobExecutionContext executingJob : executingJobs) {
Map<String, Object> map = new HashMap<String, Object>();
JobDetail jobDetail = executingJob.getJobDetail();
JobKey jobKey = jobDetail.getKey();
Trigger trigger = executingJob.getTrigger();
map.put("jobName", jobKey.getName());
map.put("jobGroupName", jobKey.getGroup());
map.put("description", "触发器:" + trigger.getKey());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
map.put("jobStatus", triggerState.name());
if (trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger) trigger;
String cronExpression = cronTrigger.getCronExpression();
map.put("jobTime", cronExpression);
}
jobList.add(map);
}
} catch (SchedulerException e) {
e.printStackTrace();
}
return jobList;
}
}
3.创建定时任务示例
- 示例代码
@Api("测试定时任务api接口")
@RestController
@RequestMapping("/api/quartz")
public class QuartzTest {
@Autowired
QuartzManagerUtil quartzManagerUtil;
@PostMapping("/testQuartz")
public void testQuartz()
{
//添加定时任务
//创建活动开启定时任务
//job名称 唯一
String jobName= QuartzJobNameConfig.getTestJobName();
//job开启组 可不唯一
String jobGroupName= QuartzGroupNameConfig.TEST_JOB_GROUP_CANCLE_ORDER;
//任务执行时间
Date jobData = new Date();
//添加参数
Map<String,Object> dataMap=new HashMap<>();
dataMap.put("param_id",111);
//添加任务前 先执行删除操作,确保新增成功
quartzManagerUtil.deleteJob(jobName,jobGroupName);
//添加定时任务
quartzManagerUtil.addJobAtTime(TestJobClass.class,jobName,jobGroupName,jobData,dataMap);
}
}
- 实际处理业务类
/**
* @description: 测试任务执行类
* @author: Sun
* @create: 2020-11-30 11:34
**/
@Component
public class TestJobClass extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
//获取参数
Integer paramId=Integer.valueOf(jobDataMap.get("param_id").toString());
//执行业务逻辑
System.out.println("执行业务逻辑"+paramId);
}
catch (Exception e){
e.printStackTrace();
}
}
}
4.可能用到工具类
- 订时任务job名称(唯一)
/**
* @description: 定时任务Job名称
* @author: Sun
* @create: 2020-11-30 11:10
**/
public class QuartzJobNameConfig {
//job 名称前缀
private static final String JOB_NAME="TEST_JOB";
//格式化名称
private static final SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmmss");
/**
* 生成唯一的 job名称
*/
public static String getTestJobName() {
//生成拍卖job名称
return JOB_NAME + sdf1.format(new Date()) + (1 + (int) (Math.random() * 10000));
}
}
- 订时任务job组名
/**
* @description: 定时任务(任务组)名称配置
* @author: Sun
* @create: 2020-11-30 11:11
**/
public class QuartzGroupNameConfig {
//测试组名称 取消订单
public static final String TEST_JOB_GROUP_CANCLE_ORDER="CANCEL_ORDER";
}
总结
这就是quartz 定时任务的基本工具类封装,应该可以完成大部分的业务场景。喜欢的可以点个赞