您的位置:首页 > 编程语言 > Java开发

Springboot2.x+Quartz分布式集群

he12118 2020-09-21 18:21 176 查看 https://blog.51cto.com/1494200

Springboot2.x+Quartz分布式集群

生产环境一般都是多节点高可用,Springboot本身自带有定时任务功能,但我们项目需求要求能对定时任务进行增,删,改,查。所以考虑引进Quartz,引入Quartz就需要考虑分布式集群,所以就有了这篇文章。

数据库脚本

Quartz数据库有11张表,既支持Mysql,也支持Oracle

Mysql

/*
Navicat MySQL Data Transfer

Source Server         : 10.19.34.3_ehr_admin
Source Server Version : 50639
Source Host           : 10.19.34.3:3306
Source Database       : attend_base_dev

Target Server Type    : MYSQL
Target Server Version : 50639
File Encoding         : 65001

Date: 2020-08-28 16:29:36
*/

-- SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `qrtz_CALENDARS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_CALENDARS`;
CREATE TABLE `qrtz_CALENDARS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`CALENDAR_NAME` varchar(200) NOT NULL,
`CALENDAR` blob NOT NULL,
PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='日历信息';

-- ----------------------------
-- Records of qrtz_CALENDARS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_FIRED_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_FIRED_TRIGGERS`;
CREATE TABLE `qrtz_FIRED_TRIGGERS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`ENTRY_ID` varchar(95) NOT NULL COMMENT '组标识',
`TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
`TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
`INSTANCE_NAME` varchar(200) NOT NULL COMMENT '当前实例的名称',
`FIRED_TIME` bigint(13) NOT NULL COMMENT '当前执行时间',
`SCHED_TIME` bigint(13) NOT NULL COMMENT '计划时间',
`PRIORITY` int(11) NOT NULL COMMENT '权重',
`STATE` varchar(16) NOT NULL COMMENT '状态:WAITING:等待 \r\nPAUSED:暂停 \r\nACQUIRED:正常执行 \r\nBLOCKED:阻塞 \r\nERROR:错误',
`JOB_NAME` varchar(200) DEFAULT NULL COMMENT '作业名称',
`JOB_GROUP` varchar(200) DEFAULT NULL COMMENT '作业组',
`IS_NONCONCURRENT` varchar(1) DEFAULT NULL COMMENT '是否并行',
`REQUESTS_RECOVERY` varchar(1) DEFAULT NULL COMMENT '是否要求唤醒',
PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
KEY `IDX_qrtz_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
KEY `IDX_qrtz_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
KEY `IDX_qrtz_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
KEY `IDX_qrtz_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
KEY `IDX_qrtz_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `IDX_qrtz_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='保存已经触发的触发器状态信息';

-- ----------------------------
-- Records of qrtz_FIRED_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_JOB_DETAILS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_JOB_DETAILS`;
CREATE TABLE `qrtz_JOB_DETAILS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`JOB_NAME` varchar(200) NOT NULL COMMENT '集群中job的名字',
`JOB_GROUP` varchar(200) NOT NULL COMMENT '集群中job的所属组的名字',
`DESCRIPTION` varchar(250) DEFAULT NULL COMMENT '描述',
`JOB_CLASS_NAME` varchar(250) NOT NULL COMMENT '作业程序类名',
`IS_DURABLE` varchar(1) NOT NULL COMMENT '是否持久',
`IS_NONCONCURRENT` varchar(1) NOT NULL COMMENT '是否并行',
`IS_UPDATE_DATA` varchar(1) NOT NULL COMMENT '是否更新',
`REQUESTS_RECOVERY` varchar(1) NOT NULL COMMENT '是否要求唤醒',
`JOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
KEY `IDX_qrtz_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
KEY `IDX_qrtz_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job 详细信息';

-- ----------------------------
-- Records of qrtz_JOB_DETAILS
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_LOCKS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_LOCKS`;
CREATE TABLE `qrtz_LOCKS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`LOCK_NAME` varchar(40) NOT NULL COMMENT '锁名称',
PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存储程序的悲观锁的信息(假如使用了悲观锁) ';

-- ----------------------------
-- Records of qrtz_LOCKS

-- ----------------------------
-- Table structure for `qrtz_PAUSED_TRIGGER_GRPS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_PAUSED_TRIGGER_GRPS`;
CREATE TABLE `qrtz_PAUSED_TRIGGER_GRPS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存放暂停掉的触发器';

-- ----------------------------
-- Records of qrtz_PAUSED_TRIGGER_GRPS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_SCHEDULER_STATE`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SCHEDULER_STATE`;
CREATE TABLE `qrtz_SCHEDULER_STATE` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`INSTANCE_NAME` varchar(200) NOT NULL COMMENT '实例名称',
`LAST_CHECKIN_TIME` bigint(13) NOT NULL COMMENT '最后的检查时间',
`CHECKIN_INTERVAL` bigint(13) NOT NULL COMMENT '检查间隔',
PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='调度器状态';

-- ----------------------------
-- Records of qrtz_SCHEDULER_STATE

-- ----------------------------
-- Table structure for `qrtz_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_TRIGGERS`;
CREATE TABLE `qrtz_TRIGGERS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
`TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
`JOB_NAME` varchar(200) NOT NULL COMMENT '作业名称',
`JOB_GROUP` varchar(200) NOT NULL COMMENT '作业组',
`DESCRIPTION` varchar(250) DEFAULT NULL COMMENT '描述',
`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL COMMENT '下次执行时间',
`PREV_FIRE_TIME` bigint(13) DEFAULT NULL COMMENT '前一次',
`PRIORITY` int(11) DEFAULT NULL COMMENT '优先权',
`TRIGGER_STATE` varchar(16) NOT NULL COMMENT '触发器状态',
`TRIGGER_TYPE` varchar(8) NOT NULL COMMENT '触发器类型',
`START_TIME` bigint(13) NOT NULL COMMENT '开始时间',
`END_TIME` bigint(13) DEFAULT NULL COMMENT '结束时间',
`CALENDAR_NAME` varchar(200) DEFAULT NULL COMMENT '日历名称',
`MISFIRE_INSTR` smallint(2) DEFAULT NULL COMMENT '失败次数',
`JOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `IDX_qrtz_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
KEY `IDX_qrtz_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
KEY `IDX_qrtz_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
KEY `IDX_qrtz_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
KEY `IDX_qrtz_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
KEY `IDX_qrtz_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
KEY `IDX_qrtz_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
KEY `IDX_qrtz_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
KEY `IDX_qrtz_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
KEY `IDX_qrtz_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
KEY `IDX_qrtz_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
KEY `IDX_qrtz_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='触发器';

-- ----------------------------
-- Records of qrtz_TRIGGERS

-- ----------------------------
-- Table structure for `qrtz_SIMPLE_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SIMPLE_TRIGGERS`;
CREATE TABLE `qrtz_SIMPLE_TRIGGERS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
`TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
`REPEAT_COUNT` bigint(7) NOT NULL COMMENT '重复次数',
`REPEAT_INTERVAL` bigint(12) NOT NULL COMMENT '重复间隔',
`TIMES_TRIGGERED` bigint(10) NOT NULL COMMENT '触发次数',
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='简单的触发器';

-- ----------------------------
-- Records of qrtz_SIMPLE_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_SIMPROP_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SIMPROP_TRIGGERS`;
CREATE TABLE `qrtz_SIMPROP_TRIGGERS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
`TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
`STR_PROP_1` varchar(512) DEFAULT NULL,
`STR_PROP_2` varchar(512) DEFAULT NULL,
`STR_PROP_3` varchar(512) DEFAULT NULL,
`INT_PROP_1` int(11) DEFAULT NULL,
`INT_PROP_2` int(11) DEFAULT NULL,
`LONG_PROP_1` bigint(20) DEFAULT NULL,
`LONG_PROP_2` bigint(20) DEFAULT NULL,
`DEC_PROP_1` decimal(13,4) DEFAULT NULL,
`DEC_PROP_2` decimal(13,4) DEFAULT NULL,
`BOOL_PROP_1` varchar(1) DEFAULT NULL,
`BOOL_PROP_2` varchar(1) DEFAULT NULL,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器';

-- ----------------------------
-- Records of qrtz_SIMPROP_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_BLOB_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_BLOB_TRIGGERS`;
CREATE TABLE `qrtz_BLOB_TRIGGERS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名',
`TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
`TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
`BLOB_DATA` blob,
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='以Blob 类型存储的触发器';

-- ----------------------------
-- Records of qrtz_BLOB_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_CRON_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_CRON_TRIGGERS`;
CREATE TABLE `qrtz_CRON_TRIGGERS` (
`SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
`TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
`TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
`CRON_EXPRESSION` varchar(120) NOT NULL COMMENT '时间表达式',
`TIME_ZONE_ID` varchar(80) DEFAULT NULL COMMENT '时区ID     nvarchar     80',
PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='定时触发器';

-- ----------------------------
-- Records of qrtz_CRON_TRIGGERS
-- ----------------------------

Oracle

create table QRTZ_CALENDARS
(
sched_name    VARCHAR2(120) not null,
calendar_name VARCHAR2(200) not null,
calendar      BLOB not null
);
alter table QRTZ_CALENDARS
add constraint PK_QRTZ_CALENDARS primary key (SCHED_NAME, CALENDAR_NAME);

create table QRTZ_FIRED_TRIGGERS
(
sched_name        VARCHAR2(120) not null,
entry_id          VARCHAR2(95) not null,
trigger_name      VARCHAR2(200) not null,
trigger_group     VARCHAR2(200) not null,
instance_name     VARCHAR2(200) not null,
fired_time        NUMBER(13) not null,
sched_time        NUMBER(13) not null,
priority          INTEGER not null,
state             VARCHAR2(16) not null,
job_name          VARCHAR2(200),
job_group         VARCHAR2(200),
is_nonconcurrent  VARCHAR2(1),
requests_recovery VARCHAR2(1)
);
alter table QRTZ_FIRED_TRIGGERS
add constraint PK_QRTZ_FIRED_TRIGGERS primary key (SCHED_NAME, ENTRY_ID);

create table QRTZ_JOB_DETAILS
(
sched_name        VARCHAR2(120) not null,
job_name          VARCHAR2(200) not null,
job_group         VARCHAR2(200) not null,
description       VARCHAR2(250),
job_class_name    VARCHAR2(250) not null,
is_durable        VARCHAR2(1) not null,
is_nonconcurrent  VARCHAR2(1) not null,
is_update_data    VARCHAR2(1) not null,
requests_recovery VARCHAR2(1) not null,
job_data          BLOB
);
alter table QRTZ_JOB_DETAILS
add constraint PK_QRTZ_JOB_DETAILS primary key (SCHED_NAME, JOB_NAME, JOB_GROUP);

create table QRTZ_LOCKS
(
sched_name VARCHAR2(120) not null,
lock_name  VARCHAR2(40) not null
);
alter table QRTZ_LOCKS
add constraint PK_QRTZ_LOCKS primary key (SCHED_NAME, LOCK_NAME);

create table QRTZ_PAUSED_TRIGGER_GRPS
(
sched_name    VARCHAR2(120) not null,
trigger_group VARCHAR2(200) not null
);
alter table QRTZ_PAUSED_TRIGGER_GRPS
add constraint PK__TRIGGER_GRPS primary key (SCHED_NAME, TRIGGER_GROUP);

create table QRTZ_SCHEDULER_STATE
(
sched_name        VARCHAR2(120) not null,
instance_name     VARCHAR2(200) not null,
last_checkin_time NUMBER(13) not null,
checkin_interval  NUMBER(13) not null
);
alter table QRTZ_SCHEDULER_STATE
add constraint PK_QRTZ_SCHEDULER_STATE primary key (SCHED_NAME, INSTANCE_NAME);

create table QRTZ_TRIGGERS
(
sched_name     VARCHAR2(120) not null,
trigger_name   VARCHAR2(200) not null,
trigger_group  VARCHAR2(200) not null,
job_name       VARCHAR2(200) not null,
job_group      VARCHAR2(200) not null,
description    VARCHAR2(250),
next_fire_time NUMBER(13),
prev_fire_time NUMBER(13),
priority       INTEGER,
trigger_state  VARCHAR2(16) not null,
trigger_type   VARCHAR2(8) not null,
start_time     NUMBER(13) not null,
end_time       NUMBER(13),
calendar_name  VARCHAR2(200),
misfire_instr  NUMBER(2),
job_data       BLOB
);

alter table QRTZ_TRIGGERS
add constraint PK_QRTZ_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_SIMPLE_TRIGGERS
(
sched_name      VARCHAR2(120) not null,
trigger_name    VARCHAR2(200) not null,
trigger_group   VARCHAR2(200) not null,
repeat_count    NUMBER(7) not null,
repeat_interval NUMBER(12) not null,
times_triggered NUMBER(10) not null
);
alter table QRTZ_SIMPLE_TRIGGERS
add constraint PK_QRTZ_SIMPLE_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_SIMPROP_TRIGGERS
(
sched_name    VARCHAR2(120) not null,
trigger_name  VARCHAR2(200) not null,
trigger_group VARCHAR2(200) not null,
str_prop_1    VARCHAR2(512),
str_prop_2    VARCHAR2(512),
str_prop_3    VARCHAR2(512),
int_prop_1    INTEGER,
int_prop_2    INTEGER,
long_prop_1   NUMBER,
long_prop_2   NUMBER,
dec_prop_1    NUMBER(13,4),
dec_prop_2    NUMBER(13,4),
bool_prop_1   VARCHAR2(1),
bool_prop_2   VARCHAR2(1)
);
alter table QRTZ_SIMPROP_TRIGGERS
add constraint PK_QRTZ_SIMPROP_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_BLOB_TRIGGERS
(
sched_name    VARCHAR2(120) not null,
trigger_name  VARCHAR2(200) not null,
trigger_group VARCHAR2(200) not null,
blob_data     BLOB
);
alter table QRTZ_BLOB_TRIGGERS
add constraint PK_QRTZ_BLOB_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_CRON_TRIGGERS
(
sched_name      VARCHAR2(120) not null,
trigger_name    VARCHAR2(200) not null,
trigger_group   VARCHAR2(200) not null,
cron_expression VARCHAR2(200) not null,
time_zone_id    VARCHAR2(80)
);
alter table QRTZ_CRON_TRIGGERS
add constraint PK_QRTZ_CRON_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

delete from QRTZ_JOB_DETAILS;
delete from QRTZ_CRON_TRIGGERS;
delete from QRTZ_BLOB_TRIGGERS;
delete from QRTZ_CALENDARS;
delete from QRTZ_FIRED_TRIGGERS;
delete from QRTZ_LOCKS;
delete from QRTZ_PAUSED_TRIGGER_GRPS;
delete from QRTZ_SCHEDULER_STATE;
delete from QRTZ_SIMPLE_TRIGGERS;
delete from QRTZ_SIMPROP_TRIGGERS;
delete from QRTZ_TRIGGERS;

Maven

我这里后台使用的是Springboot2.1

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

application.yml

quartz:
#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 #开启10个线程
threadPriority: 5 #工作者线程的优先级
threadsInheritContextClassLoaderOfInitializingThread: true
#数据库方式
job-store-type: jdbc

Bean

import org.quartz.JobDataMap;
import java.util.Date;

/**
* @program: QuartzBean
* @description:
* @author: Yuwl
* @create: 2020-06-02 18:36
**/
public class QuartzBean {

/** 任务id */
private String  id;

/** 任务名称 */
private String jobName;

/** 任务组 */
private String jobGroup;

/** 任务执行类 */
private String jobClass;

/** 任务状态 启动还是暂停*/
private Integer status;

/**
* 任务开始时间
*/
private Date startTime;

/**
* 任务循环间隔-单位:分钟
*/
private Integer interval;

/**
* 任务结束时间
*/
private Date endTime;

/** 任务运行时间表达式 */
private String cronExpression;

private JobDataMap jobDataMap;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getJobName() {
return jobName;
}

public void setJobName(String jobName) {
this.jobName = jobName;
}

public String getJobClass() {
return jobClass;
}

public void setJobClass(String jobClass) {
this.jobClass = jobClass;
}

public Integer getStatus() {
return status;
}

public void setStatus(Integer status) {
this.status = status;
}

public String getCronExpression() {
return cronExpression;
}

public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}

public Date getStartTime() {
return startTime;
}

public void setStartTime(Date startTime) {
this.startTime = startTime;
}

public Integer getInterval() {
return interval;
}

public void setInterval(Integer interval) {
this.interval = interval;
}

public Date getEndTime() {
return endTime;
}

public void setEndTime(Date endTime) {
this.endTime = endTime;
}

public JobDataMap getJobDataMap() {
return jobDataMap;
}

public void setJobDataMap(JobDataMap jobDataMap) {
this.jobDataMap = jobDataMap;
}

public String getJobGroup() {
return jobGroup;
}

public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
}

Service

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.framework.quartz.QuartzBean;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
* @program: QuartzJobService
* @description:
* @author: Yuwl
* @create: 2020-07-21 17:00
**/
@Service
public class QuartzJobService {

@Autowired
private Scheduler scheduler;

/**
* 创建定时任务Simple
* quartzBean.getInterval()==null表示单次提醒,
* 否则循环提醒(quartzBean.getEndTime()!=null)
* @param quartzBean
*/
public void createScheduleJobSimple(QuartzBean quartzBean) throws Exception{
//获取到定时任务的执行类  必须是类的绝对路径名称
//定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
// 构建定时任务信息
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
.setJobData(quartzBean.getJobDataMap())
.build();
// 设置定时任务执行方式
SimpleScheduleBuilder simpleScheduleBuilder = null;
if (quartzBean.getInterval() ==  null) { //单次
simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
} else { //循环
simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(quartzBean.getInterval());
}
// 构建触发器trigger
Trigger trigger = null;
if (quartzBean.getInterval() ==  null) { //单次
trigger = TriggerBuilder.newTrigger()
.withIdentity(quartzBean.getJobName(),ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
.withSchedule(simpleScheduleBuilder)
.startAt(quartzBean.getStartTime())
.build();
} else { //循环
trigger = TriggerBuilder.newTrigger()
.withIdentity(quartzBean.getJobName(),ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
.withSchedule(simpleScheduleBuilder)
.startAt(quartzBean.getStartTime())
.endAt(quartzBean.getEndTime())
.build();
}
scheduler.scheduleJob(jobDetail, trigger);
}

/**
* 创建定时任务Cron
* 定时任务创建之后默认启动状态
* @param quartzBean  定时任务信息类
* @throws Exception
*/
public void createScheduleJobCron(QuartzBean quartzBean) throws Exception{
//获取到定时任务的执行类  必须是类的绝对路径名称
//定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
// 构建定时任务信息
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).setJobData(quartzBean.getJobDataMap()).build();
// 设置定时任务执行方式
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
// 构建触发器trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
}

/**
* 根据任务名称暂停定时任务
* @param jobName 定时任务名称
* @param jobGroup 任务组(没有分组传值null)
* @throws Exception
*/
public void pauseScheduleJob(String jobName,String jobGroup) throws Exception{
JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
scheduler.pauseJob(jobKey);
}

/**
* 根据任务名称恢复定时任务
* @param jobName    定时任务名
* @param jobGroup 任务组(没有分组传值null)
* @throws SchedulerException
*/
public void resumeScheduleJob(String jobName,String jobGroup) throws Exception {
JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
scheduler.resumeJob(jobKey);
}

/**
* 根据任务名称立即运行一次定时任务
* @param jobName       定时任务名称
* @param jobGroup 任务组(没有分组传值null)
* @throws SchedulerException
*/
public void runOnce(String jobName,String jobGroup) throws Exception{
JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
scheduler.triggerJob(jobKey);
}

/**
* 更新定时任务Simple
* @param quartzBean  定时任务信息类
* @throws SchedulerException
*/
public void updateScheduleJobSimple(QuartzBean quartzBean) throws Exception {
//获取到对应任务的触发器
TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null);
// 设置定时任务执行方式
SimpleScheduleBuilder simpleScheduleBuilder = null;
if (quartzBean.getInterval() ==  null) { //单次
simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
} else { //循环
simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(quartzBean.getInterval());
}
// 构建触发器trigger
Trigger trigger = null;
if (quartzBean.getInterval() ==  null) { //单次
trigger = TriggerBuilder.newTrigger()
.withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
.withSchedule(simpleScheduleBuilder)
.startAt(quartzBean.getStartTime())
.build();
} else { //循环
TriggerBuilder.newTrigger()
.withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
.withSchedule(simpleScheduleBuilder)
.startAt(quartzBean.getStartTime())
.endAt(quartzBean.getEndTime())
.build();
}
//重置对应的job
scheduler.rescheduleJob(triggerKey, trigger);
}

/**
* 更新定时任务Cron
* @param quartzBean  定时任务信息类
* @throws SchedulerException
*/
public void updateScheduleJobCron(QuartzBean quartzBean) throws Exception {
//获取到对应任务的触发器
TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
//设置定时任务执行方式
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
//重新构建任务的触发器trigger
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//重置对应的job
scheduler.rescheduleJob(triggerKey, trigger);
}

/**
* 根据定时任务名称从调度器当中删除定时任务
* @param jobName   定时任务名称
* @param jobGroup 任务组(没有分组传值null)
* @throws SchedulerException
*/
public void deleteScheduleJob(String jobName,String jobGroup) throws Exception {
JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
scheduler.deleteJob(jobKey);
}

/**
* 获取任务状态
* @param jobName
* @param jobGroup 任务组(没有分组传值null)
* @return
* (" BLOCKED ", " 阻塞 ");
* ("COMPLETE", "完成");
* ("ERROR", "出错");
* ("NONE", "不存在");
* ("NORMAL", "正常");
* ("PAUSED", "暂停");
*/
public String getScheduleJobStatus(String jobName,String jobGroup) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
Trigger.TriggerState state = scheduler.getTriggerState(triggerKey);
return state.name();
}

/**
* 根据定时任务名称来判断任务是否存在
* @param jobName   定时任务名称
* @param jobGroup 任务组(没有分组传值null)
* @throws SchedulerException
*/
public Boolean checkExistsScheduleJob(String jobName,String jobGroup) throws Exception {
JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
return scheduler.checkExists(jobKey);
}

/**
* 根据任务組刪除定時任务
* @param jobGroup 任务组
* @throws SchedulerException
*/
public Boolean deleteGroupJob(String jobGroup) throws Exception {
GroupMatcher<JobKey> matcher = GroupMatcher.groupEquals(jobGroup);
Set<JobKey> jobkeySet = scheduler.getJobKeys(matcher);
List<JobKey> jobkeyList = new ArrayList<JobKey>();
jobkeyList.addAll(jobkeySet);
return scheduler.deleteJobs(jobkeyList);
}

/**
* 根据任务組批量刪除定時任务
* @param jobkeyList
* @throws SchedulerException
*/
public Boolean batchDeleteGroupJob(List<JobKey> jobkeyList) throws Exception {
return scheduler.deleteJobs(jobkeyList);
}

/**
* 根据任务組批量查询出jobkey
* @param jobGroup 任务组
* @throws SchedulerException
*/
public void batchQueryGroupJob(List<JobKey> jobkeyList,String jobGroup) throws Exception {
GroupMatcher<JobKey> matcher = GroupMatcher.groupEquals(jobGroup);
Set<JobKey> jobkeySet = scheduler.getJobKeys(matcher);
jobkeyList.addAll(jobkeySet);
}
}

Job

package com.quartz.demo.job

import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
* @program: job
* @description:
* @author: Yuwl
* @create: 2020-06-02 18:07
**/
@Component
public class MyTask extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
JobKey jobKey = context.getJobDetail().getKey();
JobDataMap map = context.getJobDetail().getJobDataMap();
String userId = map.getString("userId");
System.out.println("SimpleJob says: " + jobKey + ", userId: " + userId + " executing at " + new Date());
}
}

Controller

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.framework.quartz.QuartzBean;
import com.ruoyi.framework.quartz.service.QuartzJobService;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.ParseException;
import java.util.Date;

/**
* @program: JobController
* @description:
* @author: Yuwl
* @create: 2020-07-21 17:08
**/
@RestController
@RequestMapping("/api/quartz/")
public class JobController {

@Autowired
private QuartzJobService quartzJobService;

//创建&启动
@GetMapping("startSimpleJob")
public String startSimpleJob() throws SchedulerException, ClassNotFoundException, ParseException {
QuartzBean quartzBean = new QuartzBean();
quartzBean.setJobClass("com.quartz.demo.job.MyTask");
quartzBean.setJobName("job1");
JobDataMap map = new JobDataMap();
map.put("userId", "123456");
quartzBean.setJobDataMap(map);
Date now = new Date();
quartzBean.setStartTime(DateUtils.addSeconds(now, 10));
quartzBean.setInterval(10);
quartzBean.setEndTime(DateUtils.addMinutes(now, 1));
try {
quartzJobService.createScheduleJobSimple(quartzBean);
} catch (Exception e) {
e.printStackTrace();
}
return "startJob Success!";
}

/**
* 创建cron Job
* @param quartzBean
* @return
*/
@RequestMapping("/createCronJob")
@ResponseBody
public String  createJob(QuartzBean quartzBean)  {
try {
//进行测试所以写死
quartzBean.setJobClass("com.quartz.demo.job.MyTask");
quartzBean.setJobName("job1");
quartzBean.setCronExpression("*/5 * * * * ?");
quartzJobService.createScheduleJobCron(quartzBean);
} catch (Exception e) {
return "创建失败";
}
return "创建成功";
}

/**
* 暂停job
* @return
*/
@RequestMapping(value = {"/pauseJob/{jobName}","/pauseJob/{jobName}/{jobGroup}"})
@ResponseBody
public String  pauseJob(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
try {
quartzJobService.pauseScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
} catch (Exception e) {
return "暂停失败";
}
return "暂停成功";
}

@RequestMapping(value = {"/resume/{jobName}","/resume/{jobName}/{jobGroup}"})
@ResponseBody
public String  resume(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
try {
quartzJobService.resumeScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
} catch (Exception e) {
return "启动失败";
}
return "启动成功";
}

@RequestMapping(value = {"/delete/{jobName}","/delete/{jobName}/{jobGroup}"})
public String  delete(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
try {
quartzJobService.deleteScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
} catch (Exception e) {
return "删除失败";
}
return "删除成功";
}

@RequestMapping(value = {"/check/{jobName}","/check/{jobName}/{jobGroup}"})
public String  check(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
try {
if(quartzJobService.checkExistsScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null)){
return "存在定时任务:"+jobName;
}else{
return "不存在定时任务:"+jobName;
}
} catch (Exception e) {
return "查询任务失败";
}
}

@RequestMapping(value = {"/status/{jobName}","/status/{jobName}/{jobGroup}"})
@ResponseBody
public String  status(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
try {
return quartzJobService.getScheduleJobStatus(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
} catch (Exception e) {
return "获取状态失败";
}
//return "获取状态成功";
}

}

测试

http://localhost:8080/api/quartz/startSimpleJob

作者介绍:小林,狐小E资深开发工程师,专注移动协同办公平台的SAAS软件开发以及轻应用开发
最近开发了一款移动办公软件 狐小E

标签: