Spring boot與Quartz實現任務定時提醒


客戶經常會說到:

 

“我們要做個進度把控,給每個審核節點加上時間限制,因為如果一個節點上的任務長時間不處理,那就超時啦!”

“任務的時間限制是個很重要的東西,你們能不能做一個功能,當任務快到時間限制的時候,提醒一下該任務的負責人?”

......

 

可見,任務的時效性是一個非常重要的東西,我們應該如何實現“到了某個時間節點就去提醒別人”這個目標呢?

 

我們知道,Spring Boot是自帶有調功能的,可以用@Schedule注解實現定時任務,但是這種方法只能實現固定的時間調度。而用戶需要的是可以自定義定時任務的啟動時間。更重要的是,如果系統重啟了,那么原來內存中的定時任務就會被釋放!這是一個非常致命的問題。

 

這個時候,Quartz這個工具就派上用場了。

 

Quartz是一個優秀的開源調度框架(感謝開源組織的貢獻),具有很多優點,例如:

(1)功能強大,支持豐富的調度方法,並且支持成千上萬定時任務同時調度;

(2)支持任務的持久化,不用擔心系統在重啟之后,“忘記”之前的調度任務;

(3)支持分布式,你可以設置多個executor來執行調度任務,實現負載平衡和提升可靠性(Linkin的開源調度工具Azkaban就是基於quartz實現的)。

Quartz核心概念

Quartz有幾個核心概念,分別是:

Scheduler:任務調度器

Trigger:觸發器,它定義了調度的時間規則

Job:任務,即被調度器調度的任務

Key:包括name(名字)和group(分組),我們將trigger和job注冊到scheduler時,需要給它們賦上key。

 

Quartz核心概念的關系如圖:

                                    

(來源:IBM)

 

組件的工作過程:

 

(1)使用SchedulerFactory創建Scheduler實例

SchedulerFactory factory = new SchedulerFactory();

Scheduler scheduler = factory.getScheduler();

 

(2)創建一個任務

JobDetail job = JobBuilder.newJob(CustomJob.class).withIndentity("myJob", "myGroup").build();

CustomJob是一個自定義的定時任務類。

 

(3)創建一個觸發器,指定任務在什么時間執行

Trigger trigger = TriggerBuilder.newTrigger.withIndentity("myTrigger", "myGroup")

.startAt(targerDate).build()

其中,targetDate是一個java.util.Date類型,用於指定任務在什么時候執行。

 

(4)注冊任務到調度器

scheduler.scheduleJob(job, trigger)

把任務調度上去之后,任務就會在指定的時間執行啦。

 

在Spring Boot中使用

前面我們只是介紹了Quartz基本工作流程,那么如何在Spring Boot中使用呢?如何把定時任務持久化呢?

 

在Spring Boot 2.0版本中,已經集成了Quartz 2.3.0版本,Spring Boot已經能夠對Quartz進行自動化的配置,省去了很多人工操作,大大減輕了程序員的開發壓力

 

(1)在已有的Spring Boot項目中的Gradle文件中引入quartz-starter依賴

compile('org.springframework.boot:spring-boot-starter-quartz')

 

(2)在項目對應的數據源mysql中指定quartz的sql語句,創建所需要的表(代碼見文末)

 

(3)在application.properties里添加quartz的配置

spring.quartz.job-store-type=jdbc

spring.quartz.jdbc.initialize-schema=never

除此之外,不要我們寫入其它的配置,Spring Boot會自動為我們配置好。

這樣配置之后,所有的quartz任務會自動持久化到mysql中,不會丟失。

 

(4)在代碼中進行任務調度

// 在需要使用Scheduler的地方直接注入Scheduler,Spring Boot已經配置好了

 

Scheduler實例

@Autowire

private Scheduler scheduler;

// 任務調度

String jobKey = UUID.randomUUID().toString();

String triggerKey = UUID.randomUUID().toString();

JobDetail jobDetail = JobBuilder.newJob(CustomNotifyTask.class)

.withIdentity(jobKey, CustomTask.class.getName())

.build();

Trigger trigger = TriggerBuilder.newTrigger()

.withIdentity(triggerKey, CustomTask.class.getName())

.startAt(targetDate).build();

// 啟動調度

scheduler.scheduleJob(jobDetail, trigger);

 

CustomTask是一個任務類,它繼承了QuartzJobBean並且實現了其executeInternal接口。

 

public class CustomTask extends QuartzJobBean {

@Override

protected void executeInternal(JobExecutionContext context) {

System.out.println("hello world");

}

}

 

至此,我們展示了一個單節點持久化的Quartz調度器的使用。

Bonus:向定時任務傳遞參數

一般來說,定時任務是需要接收參數的,這樣才能實現豐富的功能。比如,我們要在定時任務中向自定義的郵箱發送郵件,那么郵件地址是可以通過參數傳遞進去的。

在Quartz框架中,向定時任務傳遞參數也是非常方便的。

 

在調度任務時,傳遞參數myNumber。

JobDetail jobDetail = JobBuilder.newJob(CustomNotifyTask.class)

.withIdentity(jobKey, CustomTask.class.getName())

.usingJobData("mynum", myNumber)

.usingJobData("email", email)

.build();

 

在執行任務時,獲取參數myNumber。

@Override

protected void executeInternal(JobExecutionContext context) {

JobDataMap dataMap = context.getJobDetail().getJobDataMap();

Integer applyId = dataMap.getInt("mynum");

String email = dataMap.getInt("email");

// .......

}

擴展:Quartz集群

雖然單個的Quartz調度實例(單機版)可以讓我們很好的進行任務的調度,但是無法滿足日益復雜的企業應用的要求,比如高可靠性,高可用性和可擴展性。如果我們調度的任務非常多,那么Quartz集群就是必須要考慮的。當一個Quartz實例崩潰的時候,集群里的另外一個實例可以快速地接替它的工作,確保Job的執行。

 

Quartz的集群配置更加復雜以下,如果對它感興趣,可以移步https://medium.com/@Hronom/spring-boot-quartz-scheduler-in-cluster-mode-457f4535104d,Quartz的更多特性等着你探索!

 

附錄代碼:

/*

Navicat MySQL Data Transfer

Source Server : local

Source Server Version : 50505

Source Host : localhost:3306

Source Database : quartz

 

Target Server Type : MYSQL

Target Server Version : 50505

File Encoding : 65001

 

Date: 2017-11-05 18:01:51

*/

 

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------

-- Table structure for basic_good_info

-- ----------------------------

DROP TABLE IF EXISTS `basic_good_info`;

CREATE TABLE `basic_good_info` (

`BGI_ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '商品編號',

`BGI_NAME` varchar(20) DEFAULT NULL COMMENT '商品名稱',

`BGI_PRICE` decimal(8,2) DEFAULT NULL COMMENT '單價',

`BGI_UNIT` varchar(10) DEFAULT NULL COMMENT '單位',

PRIMARY KEY (`BGI_ID`)

) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='商品基本信息';

-- ----------------------------

-- Table structure for qrtz_blob_triggers

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_blob_triggers`;

CREATE TABLE `qrtz_blob_triggers` (

`SCHED_NAME` varchar(120) NOT NULL,

`TRIGGER_NAME` varchar(200) NOT NULL,

`TRIGGER_GROUP` varchar(200) NOT NULL,

`BLOB_DATA` blob DEFAULT NULL,

PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),

KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),

CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- Table structure for qrtz_calendars

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_calendars`;

CREATE TABLE `qrtz_calendars` (

`SCHED_NAME` varchar(120) NOT NULL,

`CALENDAR_NAME` varchar(200) NOT NULL,

`CALENDAR` blob NOT NULL,

PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- Table structure for qrtz_cron_triggers

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_cron_triggers`;

CREATE TABLE `qrtz_cron_triggers` (

`SCHED_NAME` varchar(120) NOT NULL,

`TRIGGER_NAME` varchar(200) NOT NULL,

`TRIGGER_GROUP` varchar(200) NOT NULL,

`CRON_EXPRESSION` varchar(120) NOT NULL,

`TIME_ZONE_ID` varchar(80) DEFAULT NULL,

PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),

CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- Table structure for qrtz_fired_triggers

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_fired_triggers`;

CREATE TABLE `qrtz_fired_triggers` (

`SCHED_NAME` varchar(120) NOT NULL,

`ENTRY_ID` varchar(95) NOT NULL,

`TRIGGER_NAME` varchar(200) NOT NULL,

`TRIGGER_GROUP` varchar(200) NOT NULL,

`INSTANCE_NAME` varchar(200) NOT NULL,

`FIRED_TIME` bigint(13) NOT NULL,

`SCHED_TIME` bigint(13) NOT NULL,

`PRIORITY` int(11) NOT NULL,

`STATE` varchar(16) NOT NULL,

`JOB_NAME` varchar(200) DEFAULT NULL,

`JOB_GROUP` varchar(200) DEFAULT NULL,

`IS_NONCONCURRENT` varchar(1) DEFAULT NULL,

`REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,

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;

-- ----------------------------

-- Table structure for qrtz_job_details

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_job_details`;

CREATE TABLE `qrtz_job_details` (

`SCHED_NAME` varchar(120) NOT NULL,

`JOB_NAME` varchar(200) NOT NULL,

`JOB_GROUP` varchar(200) NOT NULL,

`DESCRIPTION` varchar(250) DEFAULT NULL,

`JOB_CLASS_NAME` varchar(250) NOT NULL,

`IS_DURABLE` varchar(1) NOT NULL,

`IS_NONCONCURRENT` varchar(1) NOT NULL,

`IS_UPDATE_DATA` varchar(1) NOT NULL,

`REQUESTS_RECOVERY` varchar(1) NOT NULL,

`JOB_DATA` blob DEFAULT NULL,

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;

-- ----------------------------

-- Table structure for qrtz_locks

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_locks`;

CREATE TABLE `qrtz_locks` (

`SCHED_NAME` varchar(120) NOT NULL,

`LOCK_NAME` varchar(40) NOT NULL,

PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- 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,

`TRIGGER_GROUP` varchar(200) NOT NULL,

PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- Table structure for qrtz_scheduler_state

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_scheduler_state`;

CREATE TABLE `qrtz_scheduler_state` (

`SCHED_NAME` varchar(120) NOT NULL,

`INSTANCE_NAME` varchar(200) NOT NULL,

`LAST_CHECKIN_TIME` bigint(13) NOT NULL,

`CHECKIN_INTERVAL` bigint(13) NOT NULL,

PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- Table structure for qrtz_simple_triggers

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_simple_triggers`;

CREATE TABLE `qrtz_simple_triggers` (

`SCHED_NAME` varchar(120) NOT NULL,

`TRIGGER_NAME` varchar(200) NOT NULL,

`TRIGGER_GROUP` varchar(200) NOT NULL,

`REPEAT_COUNT` bigint(7) NOT NULL,

`REPEAT_INTERVAL` bigint(12) NOT NULL,

`TIMES_TRIGGERED` bigint(10) NOT NULL,

PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),

CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- Table structure for qrtz_simprop_triggers

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_simprop_triggers`;

CREATE TABLE `qrtz_simprop_triggers` (

`SCHED_NAME` varchar(120) NOT NULL,

`TRIGGER_NAME` varchar(200) NOT NULL,

`TRIGGER_GROUP` varchar(200) NOT NULL,

`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`),

CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------

-- Table structure for qrtz_triggers

-- ----------------------------

DROP TABLE IF EXISTS `qrtz_triggers`;

CREATE TABLE `qrtz_triggers` (

`SCHED_NAME` varchar(120) NOT NULL,

`TRIGGER_NAME` varchar(200) NOT NULL,

`TRIGGER_GROUP` varchar(200) NOT NULL,

`JOB_NAME` varchar(200) NOT NULL,

`JOB_GROUP` varchar(200) NOT NULL,

`DESCRIPTION` varchar(250) DEFAULT NULL,

`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,

`PREV_FIRE_TIME` bigint(13) DEFAULT NULL,

`PRIORITY` int(11) DEFAULT NULL,

`TRIGGER_STATE` varchar(16) NOT NULL,

`TRIGGER_TYPE` varchar(8) NOT NULL,

`START_TIME` bigint(13) NOT NULL,

`END_TIME` bigint(13) DEFAULT NULL,

`CALENDAR_NAME` varchar(200) DEFAULT NULL,

`MISFIRE_INSTR` smallint(2) DEFAULT NULL,

`JOB_DATA` blob DEFAULT NULL,

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`),

CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM