Springboot2.x+Quartz分佈式集羣

Springboot2.x+Quartz分佈式集羣

生產環境通常都是多節點高可用,Springboot自己自帶有定時任務功能,但咱們項目需求要求能對定時任務進行增,刪,改,查。因此考慮引進Quartz,引入Quartz就須要考慮分佈式集羣,因此就有了這篇文章。java

數據庫腳本

Quartz數據庫有11張表,既支持Mysql,也支持Oracleweb

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.1spring

<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/startSimpleJobsql

做者介紹:小林,狐小E資深開發工程師,專一移動協同辦公平臺的SAAS軟件開發以及輕應用開發
最近開發了一款移動辦公軟件 狐小E數據庫

相關文章
相關標籤/搜索