Quartz入门学习
文章目录
一, Quartz介紹
Quartz是一個完全由Java編寫的開源作業調度框架, 為在Java應用程序中進行作業調度提供簡單卻強大的機制. Quartz允許程序開發人員根據時間的間隔來調度作業, 它實現了作業和觸發器的多懟多的關係, 還能把多個作業與不同的觸發器關聯.
1.1 Quartz核心概念
-
Job : 表示一個工作, 要執行的具體內容, 此接口中只有一個方法
void execute(JobExecutionContext context)
-
JobDetail : 表示一個具體的可執行的調度程序, Job是這個可執行調度程序所要執行的內容, 另外JobDetail還包含了這個任務調度的方案和策略.
-
Trigger : 代表一個調度參數的配置, 什麼時候去調
-
Scheduler : 代表一個調度容器, 一個調度容器中可以註冊多個JobDetail和Trigger. 當Trigger於JobDetail組合, 就可以被Scheduler容器調度了.
1.2 Quartz API
Quartz API的關鍵接口是:
- Scheduler: 於調度程序交互的主要API.
- Job : 調度器執行的任務組件需要實現的接口
- JobDetail : 用於定義作業的實例.
- Trigger(即觸發器) : 定義執行給定作業的計劃的組件.
- JobBuilder : 用於定義/構建JobDetail實例, 用於定義作業的實例.
- TriggerBuilder : 用於定義/構建觸發器實例.
Scheduler的生命期, 從SchedulerFactory創建它時開始, 到Scheduler調用shutdown()方法時結束; Scheduler被創建後, 可以增加, 刪除和列舉Job和Trigger, 以及執行其他與調度相關的操作(如暫停Trigger). 但是, Scheduler只有在調用start()方法後, 才會真正地觸發trigger(即執行job).
Trigger用於觸發job的執行, 最常用的主要是SimpleTrigger和CronTrigger.
- SimpleTrigger主要用於一次性執行的job(只在某個特定的時間點執行一次), 或者job在特定的時間點執行, 重複執行N次, 每次執行間隔T個時間單位
- CronTrigger使用了cron, 在基於日曆的調度上非常有用.
1.3 Job和JobDetail
我们在創建JobDetail時, 將要執行的job的類名會傳給JobDetail, scheduler就知道了要執行何種類型的job. 每次當scheduler執行job時, 在調用其execute()方法之前會創建該類的一個新的實例.
當一個trigger被觸發時, 與之關聯的JobDetail實例會被加載, JobDetail引用的job類通過配置在Scheduler上的JobFactory進行初始化. 默認的JobFactory實現, 僅僅是調用job類的newInstance()方法, 然後嘗試調用JobDataMap中的key的setter方法.
二, 簡單定時任務實例
2.1 普通Demo
定義任務類MyJob
package com.lmc.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
/**
* @author: lmc
* @Description: 任務類
* @version: 1.0
* @date: 2020/9/16 17:07
*/
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Object tv1 = jobExecutionContext.getTrigger().getJobDataMap().get("t1");
Object jv1 = jobExecutionContext.getJobDetail().getJobDataMap().get("j1");
Object sv1 = null;
try {
sv1 = jobExecutionContext.getScheduler().getContext().get("skey");
} catch (SchedulerException e) {
e.printStackTrace();
}
System.out.println("===============================任務正在進行" + System.currentTimeMillis() + "==============================");
System.out.println("tv1 = " + tv1);
System.out.println("jv1 = " + jv1);
System.out.println("sv1 = " + sv1);
}
}
主類:
package com.lmc.quartz;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
/**
* @author: Test
* @Description: 描述信息
* @version: 1.0
* @date: 2020/9/16 17:22
*/
public class Test {
public static void main(String[] args) throws SchedulerException {
//創建一個scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.getContext().put("skey", "svalue");
//創建一個trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1").usingJobData("t1", "tv1")
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).repeatForever())
.build();
trigger.getJobDataMap().put("t2", "tv2");
//創建一個job
JobDetail job = JobBuilder.newJob(MyJob.class)
.usingJobData("j1", "jv1")
.withIdentity("myjob", "mygroup")
.build();
job.getJobDataMap().put("j2", "jv2");
//註冊trigger並啟動scheduler
scheduler.scheduleJob(job, trigger);
scheduler.start();
}
}
2.2 Boot
Quartz配置類 :
package com.lmc.quartz;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
/**
* @author: QuartzConfig
* @Description: quartz配置類
* @version: 1.0
* @date: 2020/9/18 9:10
*/
@Configuration
public class QuartzConfig {
@Bean
public JobDetail getJobDetail() {
return JobBuilder.newJob(MyJob.class)
.withDescription("this is a job")
.withIdentity("job1", "jGroup1")
.storeDurably().build();
}
@Bean
public Trigger getTrigger() {
CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule("0 0 29 8 * * ?");
return TriggerBuilder.newTrigger().forJob(getJobDetail())
.withDescription("this is a trigger")
.withIdentity("trigger1", "Group1")
.startAt(new Date())
.withSchedule(builder)
.build();
}
}
啟動類 :
package com.lmc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class EurekaProviderApplication8001 {
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication8001.class, args);
}
}
三, Trigger
Trigger用於觸發job的執行, Quartz中有五種類型的Trigger :SimpleTrigger, CronTrigger, DateIntervalTrigger, NthIncludedDayTrigger和Calendar類. 最常用的主要是SimpleTrigger和CronTrigger.
trigger屬性:
- jobKey : 當trigger觸發時被執行的job的身份;
- startTime : 設置trigger第一次觸發的時間, 該屬性的值是Date類型, 表示某個指定的時間點; 有些類型的trigger, 會在設置的startTime時立刻觸發, 有些類型的trigger, 表示其觸發是在startTime之後開始生效.
- endTime :表示trigger失效的時間點
- priority : 優先級. Quartz如果沒有足夠的資源同時觸發所有的trigger, 這種情況下, 可以控制哪些trigger優先使用Quartz的工作線程.
3.1 SimpleTrigger
SimpleTrigger可以滿足的調度需求是 : 在具體的時間點執行一次, 或者在具體的時間點執行, 並且以指定的間隔重複執行若干次. SimpleTrigger的屬性包括 : 開始時間, 結束時間, 重複次數以及重複的間隔. 重複次數, 可以是0, 正整數, 以及常量SimpleTrigger.REPEAT_INDEFINTELY. 重複的間隔, 必須是0, 或者long型的正數, 表示毫秒. 如果重複間隔為0, trigger將會以重複次數並發執行
指定時間開始觸發, 只執行一次, 不重複
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1", "group1")
.usingJobData("t1", "tv1")
//指定時間觸發
.startAt(futureDate(5, IntervalUnit.MINUTE))
.forJob("job1", "group")
.build();
指定時間觸發, 重複執行
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1", "group1")
//5分鐘後觸發
.startAt(futureDate(5, IntervalUnit.MINUTE))
//每10秒執行一次, 執行10次
.withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(10))
.forJob("job1", "group")
.build();
立即觸發, 重複執行, 直到某一時間
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1", "group1")
//每10秒執行一次, 執行10次
.withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever())
//22:00停止執行
.endAt(dateOf(22, 0, 0))
.forJob("job1", "group")
.build();
在下一個小時的整點觸發, 重複執行
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1", "group1")
//下一小時整點觸發
.startAt(evenHourDate(null)) .withSchedule(simpleSchedule().withIntervalInHours(1).repeatForever())
.build();
3.2 CronTrigger
CronTrigger觸發器可以像日曆那樣按日程觸發任務, 是一個基於日曆的作業調度器.
cron表達式: 用來配置CronTrigger實例, 由七個部分組成
位置 | 時間域 | 允許值 |
---|---|---|
1 | 秒 | 0-59 |
2 | 分鐘 | 0-59 |
3 | 小時 | 0-23 |
4 | 日期 | 1-31 |
5 | 月份 | 1-12 |
6 | 星期 | 1-7 |
7 | 年份(可選) |
特殊符號 :
特殊符號 | 含義 |
---|---|
* | 用來表示域中"每個"可能的值 |
? | 表示不指定值, 使用的場景為不需要當前設置這個字段的值. 例如"月份的日期" 和"星期中的日期" |
- | 表示區間 |
, | 表示指定多個值 |
/ | 表示值的增量, 例如分鐘域寫入’0/15’, 表示"每隔15分鐘, 從0開始" |
L | 'last’的縮寫 |
代碼實現:
CronTrigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(cronSchedule("0 0 29 8 * * ?"))
.forJob("job1", "group")
.build();
四, Listener
4.1 JobListener
任務監聽器需要實現JobListener接口
package com.lmc.quartz;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
/**
* @author: MyJobListener
* @Description: 描述信息
* @version: 1.0
* @date: 2020/9/17 15:37
*/
public class MyJobListener implements JobListener {
@Override
public String getName() {
return "myJobListener";
}
/**
* 任務執行之前執行
* @param jobExecutionContext
*/
@Override
public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
System.out.println("=====================任務即將開始" + System.currentTimeMillis() + "=====================");
}
/**
* 這個方法正常情況下不執行, 但是如果當TriggerListener中的vetoJobExecution方法返回true時, 就執行這個方法
* @param jobExecutionContext
*/
@Override
public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
}
/**
* 任務執行完成後執行
* @param jobExecutionContext
* @param e
*/
@Override
public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
System.out.println("=====================任務已完成" + System.currentTimeMillis() + "======================");
}
}
方法解釋 :
- getName() : 指定監聽器名稱
- jobToBeExecuted() : 任務執行之前調用
- jobWasExecuted() : 任務執行完成後調用
4.2 TriggerListener
trigger監聽器要實現TriggerListener接口
package com.lmc.quartz;
import org.quartz.JobExecutionContext;
import org.quartz.Trigger;
import org.quartz.TriggerListener;
/**
* @author: MyTriggerListener
* @Description: 描述信息
* @version: 1.0
* @date: 2020/9/17 16:15
*/
public class MyTriggerListener implements TriggerListener {
@Override
public String getName() {
return "myTriggerListener";
}
/**
* Trigger被激發, 它關聯的job即將被運行
* @param trigger
* @param jobExecutionContext
*/
@Override
public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
System.err.println("triggerFired");
}
/**
* Trigger被激發, 它關聯的job即將被運行, 先執行triggerFired
* @param trigger
* @param jobExecutionContext
* @return
*/
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
System.err.println("vetoJobExecution");
return false;
}
/**
* 當trigger錯過被激發時執行, 比如當前時間有很多觸發器都需要執行, 但是線程池中數量有限, 那麼有的觸發器就有可能超時, 錯過這一輪的觸發
* @param trigger
*/
@Override
public void triggerMisfired(Trigger trigger) {
System.err.println("triggerMisfired");
}
/**
* 任務完成時觸發
* @param trigger
* @param jobExecutionContext
* @param completedExecutionInstruction
*/
@Override
public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
System.err.println("triggerComplete");
}
}
方法解釋 :
- getName : 指定觸發器名稱
- triggerFired : Trigger被激發, 它關聯的job即將被運行
- vetoJobExecution : Trigger被激發, 它關聯的job即將被運行, 先執行triggerFired
- triggerMisfired : 當trigger錯過被激發時執行, 比如當前時間有很多觸發器都需要執行, 但是線程池中數量有限, 那麼有的觸發器就有可能超時, 錯過這一輪的觸發
- triggerComplete : 任務完成時觸發
4.3 SchedulerListener
SchedulerListener非常類似於TriggerListener和JobListener.它包括了: 添加job/trigger, 刪除job/trigger, 調度程序中的嚴重錯誤, 關閉調度程序通知等.