Quartz 教程

1、關於 Quartz

Quartz logo

  • Quartz 是一個徹底由 Java 編寫的開源做業調度框架,爲在 Java 應用程序中進行做業調度提供了簡單卻強大的機制。
  • Quartz 能夠與 J2EE 與 J2SE 應用程序相結合也能夠單獨使用。
  • Quartz 容許程序開發人員根據時間的間隔來調度做業。
  • Quartz 實現了做業和觸發器的多對多的關係,還能把多個做業與不一樣的觸發器關聯。

2、Quartz 核心概念

核心組件

  • Scheduler:調度容器
  • Job:Job接口類,即被調度的任務
  • JobDetail :Job的描述類,job執行時的依據此對象的信息反射實例化出Job的具體執行對象。
  • Trigger:觸發器,存放Job執行的時間策略。用於定義任務調度時間規則。
  • JobStore: 存儲做業和調度期間的狀態
  • Calendar:指定排除的時間點(如排除法定節假日)

job

Job 是一個接口,只有一個方法 void execute(JobExecutionContext context),開發者實現接口來定義任務。JobExecutionContext 類提供了調度上下文的各類信息。Job 運行時的信息保存在 JobDataMap 實例中。例如:java

public class HelloJob implements BaseJob {
    private static Logger _log = LoggerFactory.getLogger(HelloJob.class);  
    public HelloJob() { }  
    public void execute(JobExecutionContext context) throws JobExecutionException {
        _log.error("Hello Job執行時間: " + new Date());
    }
}

JobDetailImpl 類 / JobDetail 接口

JobDetailImpl類實現了JobDetail接口,用來描述一個 job,定義了job全部屬性及其 get/set 方法。下面是 job 內部的主要屬性:mysql

屬性名 說明
class 必須是job實現類(好比JobImpl),用來綁定一個具體job
name job 名稱。若是未指定,會自動分配一個惟一名稱。全部job都必須擁有一個惟一name,若是兩個 job 的name重複,則只有最前面的 job 能被調度
group job 所屬的組名
description job描述
durability 是否持久化。若是job設置爲非持久,當沒有活躍的trigger與之關聯的時候,job 會自動從scheduler中刪除。也就是說,非持久job的生命期是由trigger的存在與否決定的
shouldRecover 是否可恢復。若是 job 設置爲可恢復,一旦 job 執行時scheduler發生hard shutdown(好比進程崩潰或關機),當scheduler重啓後,該job會被從新執行
jobDataMap 除了上面常規屬性外,用戶能夠把任意kv數據存入jobDataMap,實現 job 屬性的無限制擴展,執行 job 時可使用這些屬性數據。此屬性的類型是JobDataMap,實現了Serializable接口,可作跨平臺的序列化傳輸

Trigger

是一個類,描述觸發Job執行的時間觸發規則。主要有 SimpleTriggerCronTrigger 這兩個子類。當僅需觸發一次或者以固定時間間隔週期執行,SimpleTrigger是最適合的選擇;而CronTrigger則能夠經過Cron表達式定義出各類複雜時間規則的調度方案:如每早晨9:00執行,周1、周3、週五下午5:00執行等;git

如下是 trigger 的屬性:github

屬性名 屬性類型 說明
name 全部trigger通用 trigger名稱
group 全部trigger通用 trigger所屬的組名
description 全部trigger通用 trigger描述
calendarName 全部trigger通用 日曆名稱,指定使用哪一個Calendar類,常常用來從trigger的調度計劃中排除某些時間段
misfireInstruction 全部trigger通用 錯過job(未在指定時間執行的job)的處理策略,默認爲MISFIRE_INSTRUCTION_SMART_POLICY。詳見這篇blog^Quartz misfire
priority 全部trigger通用 優先級,默認爲5。當多個trigger同時觸發job時,線程池可能不夠用,此時根據優先級來決定誰先觸發
jobDataMap 全部trigger通用 同job的jobDataMap。假如job和trigger的jobDataMap有同名key,經過getMergedJobDataMap()獲取的jobDataMap,將以trigger的爲準
startTime 全部trigger通用 觸發開始時間,默認爲當前時間。決定什麼時間開始觸發job
endTime 全部trigger通用 觸發結束時間。決定什麼時間中止觸發job
nextFireTime SimpleTrigger私有 下一次觸發job的時間
previousFireTime SimpleTrigger私有 上一次觸發job的時間
repeatCount SimpleTrigger私有 需觸發的總次數
timesTriggered SimpleTrigger私有 已經觸發過的次數
repeatInterval SimpleTrigger私有 觸發間隔時間

Calendar

org.quartz.Calendarjava.util.Calendar不一樣,它是一些日曆特定時間點的集合(能夠簡單地將org.quartz.Calendar看做java.util.Calendar的集合——java.util.Calendar表明一個日曆時間點,無特殊說明後面的Calendar即指org.quartz.Calendar)。一個Trigger能夠和多個Calendar關聯,以便排除或包含某些時間點。假設,咱們安排每週星期一早上10:00執行任務,可是若是碰到法定的節日,任務則不執行,這時就須要在Trigger觸發機制的基礎上使用Calendar進行定點排除。sql

Scheduler

調度器,表明一個Quartz的獨立運行容器,比如一個『大管家』,這個大管家應該能夠接受 Job, 而後按照各類Trigger去運行,TriggerJobDetail能夠註冊到Scheduler中,二者在Scheduler中擁有各自的組及名稱,組及名稱是Scheduler查找定位容器中某一對象的依據,Trigger的組及名稱必須惟一,JobDetail的組和名稱也必須惟一(但能夠和Trigger的組和名稱相同,由於它們是不一樣類型的)。Scheduler定義了多個接口方法,容許外部經過組及名稱訪問和控制容器中Trigger和JobDetail。數據庫

image Scheduler 能夠將 Trigger 綁定到某一 JobDetail 中,這樣當 Trigger 觸發時,對應的 Job 就被執行。能夠經過 SchedulerFactory建立一個 Scheduler 實例。Scheduler 擁有一個 SchedulerContext,它相似於 ServletContext,保存着 Scheduler 上下文信息,Job 和 Trigger 均可以訪問 SchedulerContext 內的信息。SchedulerContext 內部經過一個 Map,以鍵值對的方式維護這些上下文數據,SchedulerContext 爲保存和獲取數據提供了多個 put() 和 getXxx() 的方法。能夠經過Scheduler# getContext()獲取對應的SchedulerContext實例;併發

ThreadPool

Scheduler 使用一個線程池做爲任務運行的基礎設施,任務經過共享線程池中的線程提升運行效率。框架

進行一個定時任務的簡單實例

public class JobTest implements BaseJob {
	private static org.slf4j.Logger log = LoggerFactory.getLogger(JobTest.class);

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		log.error("JobTest 執行時間: " + new Date());
	}
}
@Test
public void quartzTest() throws SchedulerException{
    // 1. 建立 SchedulerFactory
    SchedulerFactory factory = new StdSchedulerFactory();
    // 2. 從工廠中獲取調度器實例
    Scheduler scheduler = factory.getScheduler();

    // 3. 引進做業程序
    JobDetail jobDetail = JobBuilder.newJob(JobTest.class).withDescription("this is a ram job") //job的描述
            .withIdentity("jobTest", "jobTestGrip") //job 的name和group
            .build();

    long time=  System.currentTimeMillis() + 3*1000L; //3秒後啓動任務
    Date statTime = new Date(time);

    // 4. 建立Trigger
    //使用SimpleScheduleBuilder或者CronScheduleBuilder
    Trigger trigger = TriggerBuilder.newTrigger()
            .withDescription("this is a cronTrigger")
            .withIdentity("jobTrigger", "jobTriggerGroup")
            //.withSchedule(SimpleScheduleBuilder.simpleSchedule())
            .startAt(statTime)  //默認當前時間啓動
            .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")) //兩秒執行一次
            .build();

    // 5. 註冊任務和定時器
    scheduler.scheduleJob(jobDetail, trigger);

    // 6. 啓動 調度器
    scheduler.start();
    _log.info("啓動時間 : " + new Date());
}

3、Quartz 設計分析

quartz.properties文件

Quartz 有一個叫作quartz.properties的配置文件,它容許你修改框架運行時環境。缺省是使用 Quartz.jar 裏面的quartz.properties 文件。你應該建立一個 quartz.properties 文件的副本而且把它放入你工程的 classes 目錄中以便類裝載器找到它。ide

// 調度標識名 集羣中每個實例都必須使用相同的名稱 (區分特定的調度器實例) 
org.quartz.scheduler.instanceName:DefaultQuartzScheduler 
// ID設置爲自動獲取 每個必須不一樣 (全部調度器實例中是惟一的) 
org.quartz.scheduler.instanceId :AUTO 
// 數據保存方式爲持久化 
org.quartz.jobStore.class :org.quartz.impl.jdbcjobstore.JobStoreTX 
// 表的前綴 
org.quartz.jobStore.tablePrefix : QRTZ_ 
// 設置爲TRUE不會出現序列化非字符串類到 BLOB 時產生的類版本問題 
// org.quartz.jobStore.useProperties : true 
// 加入集羣 true 爲集羣 false不是集羣 
org.quartz.jobStore.isClustered : false 
// 調度實例失效的檢查時間間隔 
org.quartz.jobStore.clusterCheckinInterval:20000 
// 允許的最大做業延長時間 
org.quartz.jobStore.misfireThreshold :60000 
// ThreadPool 實現的類名 
org.quartz.threadPool.class:org.quartz.simpl.SimpleThreadPool 
// 線程數量 
org.quartz.threadPool.threadCount : 10 
// 線程優先級 
// threadPriority 屬性的最大值是常量 java.lang.Thread.MAX_PRIORITY,等於10。最小值爲常量 java.lang.Thread.MIN_PRIORITY,爲1
org.quartz.threadPool.threadPriority : 5
// 自建立父線程 
//org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true 
// 數據庫別名 
org.quartz.jobStore.dataSource : qzDS 
// 設置數據源 
org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver 
org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/quartz 
org.quartz.dataSource.qzDS.user:root 
org.quartz.dataSource.qzDS.password:123456 
org.quartz.dataSource.qzDS.maxConnection:10

Quartz 調度器

Quartz框架的核心是調度器。調度器負責管理Quartz應用運行時環境。啓動時,框架初始化一套worker線程,這套線程被調度器用來執行預約的做業。這就是 Quartz 怎樣能併發運行多個做業的原理。Quartz 依賴一套鬆耦合的線程池管理部件來管理線程環境。工具

兩種做業存儲方式

1. RAMJobStore

- 一般的內存來持久化調度程序信息。這種做業存儲類型最容易配置、構造和運行。
- 由於這種方式的調度程序信息是被分配到 JVM 內存中,因此,當應用程序中止運行時,全部調度信息將被丟失。若是你須要在從新啓動之間持久化調度信息,則將須要第二種類型的做業存儲。

2. JDBC做業存儲

- 須要JDBC驅動程序和後臺數據庫來持久化調度程序信息(支持集羣)
表關係和解釋

表關係

表名稱 說明
qrtz_blob_triggers Trigger做爲Blob類型存儲(用於Quartz用戶用JDBC建立他們本身定製的Trigger類型,JobStore 並不知道如何存儲實例的時候)
qrtz_calendars 以Blob類型存儲Quartz的Calendar日曆信息, quartz可配置一個日從來指定一個時間範圍
qrtz_cron_triggers 存儲Cron Trigger,包括Cron表達式和時區信息。
qrtz_fired_triggers 存儲與已觸發的Trigger相關的狀態信息,以及相聯Job的執行信息
qrtz_job_details 存儲每個已配置的Job的詳細信息
qrtz_locks 存儲程序的非觀鎖的信息(假如使用了悲觀鎖)
qrtz_paused_trigger_graps 存儲已暫停的Trigger組的信息
qrtz_scheduler_state 存儲少許的有關 Scheduler的狀態信息,和別的 Scheduler 實例(假如是用於一個集羣中)
qrtz_simple_triggers 存儲簡單的 Trigger,包括重複次數,間隔,以及已觸的次數
qrtz_triggers 存儲已配置的 Trigger的信息
qrzt_simprop_triggers

利用 SpringBoot + Quartz 搭建的界面化的 Demo

在網上找到一個搭好的 Demo,感謝大神!原文: Spring Boot集成持久化Quartz定時任務管理和界面展現

本工程所用到的技術或工具

Spring Boot
Mybatis
Quartz
PageHelper
VueJS
ElementUI
MySql數據庫

先看圖:

效果圖.png 新建任務.png

源碼地址

參考資料

相關文章
相關標籤/搜索