日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

任务调度之Quartz1

發布時間:2024/4/13 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 任务调度之Quartz1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目標

1、了解任務調度的應用場景和Quartz的基本特性

2、掌握Quartz Java編程和Spring集成的使用

3、掌握Quartz動態調度和集群部署的實現

4、理解Quartz原理與線程模型

今天你將學到:

1、除了下視頻下圖片,定時任務還可以干什么?

2、當我們在用Spring Task的時候,我們在用什么?

3、節假日購買理財不計息,怎么實現?

4、任務跑完給管理員發一條短信,怎么實現?

5、明明配置了線程池,怎么就變成單線程了?

6、怎么kill一個進程里面的一個任務?

7、Quartz的幕后角色:包工頭、工人、項目經理

8、當我想要任務重復執行的時候,為什么沒有重復執行?

內容定位

適合沒有用過Quartz或者只會Quartz基本配置的同學

說明:基于最新穩定版本2.3.0

漫談任務調度

什么時候需要任務調度?

任務調度的背景

在業務系統中有很多這樣的場景:

1、賬單日或者還款日上午10 點,給每個信用卡客戶發送賬單通知,還款通知。如何判斷客戶的賬單日、還款日,完成通知的發送?

2、銀行業務系統,夜間要完成跑批的一系列流程,清理數據,下載文件,解析文件,對賬清算、切換結算日期等等。如何觸發一系列流程的執行?

3、金融機構跟人民銀行二代支付系統對接,人民銀行要求低于5W 的金額(小額支付)半個小時打一次包發送,以緩解并發壓力。所以,銀行的跨行轉賬分成了多個流程:錄入、復核、發送。如何把半個小時以內的所有數據一次性發送?

類似于這種1、基于準確的時刻或者固定的時間間隔觸發的任務,或者2、有批量數據需要處理,或者3、要實現兩個動作解耦的場景,我們都可以用任務調度來實現。

任務調度需求分析

任務調度的實現方式有很多,如果要實現我們的調度需求,我們對這個工具有什么樣的基本要求呢?

基本需求

1)可以定義觸發的規則,比如基于時刻、時間間隔、表達式。

2)可以定義需要執行的任務。比如執行一個腳本或者一段代碼。任務和規則是分開的。

3)集中管理配置,持久配置。不用把規則寫在代碼里面,可以看到所有的任務配置,方便維護。重啟之后任務可以再次調度——配置文件或者配置中心。

4)支持任務的串行執行,例如執行A 任務后再執行B 任務再執行C 任務。

5)支持多個任務并發執行,互不干擾(例如ScheduledThreadPoolExecutor)。

6)有自己的調度器,可以啟動、中斷、停止任務。

7)容易集成到Spring。

任務調度工具對比

層次舉例特點
操作系統Linux crontab
Windows 計劃任務
只能執行簡單腳本或者命令
數據庫MySQL、Oracle可以操作數據。不能執行Java 代碼
工具Kettle可以操作數據,執行腳本。沒有集中配置
開發語言JDK Timer、ScheduledThreadPoolTimer:單線程
JDK1.5 之后:ScheduledThreadPool(Cache、Fiexed、
Single):沒有集中配置,日程管理不夠靈活
容器Spring Task、@Scheduled不支持集群
分布式框架XXL-JOB,Elastic-Job?
package com.leon.jdktimer;import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimerTask;public class TestTimerTask extends TimerTask {/*** 此計時器任務要執行的操作。*/public void run() {Date executeTime = new Date(this.scheduledExecutionTime());String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());System.out.println("任務執行了:" + dateStr);} } package com.leon.jdktimer;import java.util.Timer; import java.util.TimerTask;public class TestTimer {public static void main(String[] args) {Timer timer = new Timer();TimerTask task = new TestTimerTask();timer.schedule(task, 5000L, 1000L);} }

@Scheduled 也是用JUC 的ScheduledExecutorService 實現的

Scheduled(cron = “0 15 10 15 * ?”)

1、ScheduledAnnotationBeanPostProcessor 的postProcessAfterInitialization 方法將@Scheduled 的方法包裝為指定的task
添加到ScheduledTaskRegistrar 中

2、ScheduledAnnotationBeanPostProcessor 會監聽Spring 的容器初始化事件, 在Spring 容器初始化完成后進行TaskScheduler 實現類實例的查找,若發現有SchedulingConfigurer 的實現類實例,則跳過3

3、查找TaskScheduler 的實現類實例默認是通過類型查找,若有多個實現則會查找名字為"taskScheduler"的實現Bean,若沒有找到則在ScheduledTaskRegistrar 調度任務的時候會創建一個newSingleThreadScheduledExecutor , 將TaskScheduler 的實現類實例設置到ScheduledTaskRegistrar 屬性中

4、ScheduledTaskRegistrar 的scheduleTasks 方法觸發任務調度

5、真正調度任務的類是TaskScheduler 實現類中的ScheduledExecutorService,由J.U.C 提供

Quartz 基本介紹

官網:http://www.quartz-scheduler.org/

Quartz 的意思是石英,像石英表一樣精確。

Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application -
from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex
schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java
components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many
enterprise-class features, such as support for JTA transactions and clustering.

Quatz 是一個特性豐富的,開源的任務調度庫,它幾乎可以嵌入所有的Java 程序,從很小的獨立應用程序到大型商業系統。Quartz 可以用來創建成百上千的簡單的或者復雜的任務,這些任務可以用來執行任何程序可以做的事情。Quartz 擁有很多企業級的特性,包括支持JTA 事務和集群。

Quartz 是一個老牌的任務調度系統,98 年構思,01 年發布到sourceforge。現在更新比較慢,因為已經非常成熟了。

https://github.com/quartz-scheduler/quartz

Quartz 的目的就是讓任務調度更加簡單,開發人員只需要關注業務即可。他是用Java 語言編寫的(也有.NET 的版本)。Java 代碼能做的任何事情,Quartz 都可以調度。

特點:

精確到毫秒級別的調度

可以獨立運行,也可以集成到容器中

支持事務(JobStoreCMT )

支持集群

支持持久化

Quartz Java 編程

http://www.quartz-scheduler.org/documentation/quartz-2.3.0/
http://www.quartz-scheduler.org/documentation/quartz-2.3.0/quick-start.html

引入依賴

<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version> </dependency>

默認配置文件

org.quartz.core 包下,有一個默認的配置文件,quartz.properties。當我們沒有定義一個同名的配置文件的時候,就會使用默認配置文件里面的配置。

org.quartz.scheduler.instanceName: DefaultQuartzScheduler org.quartz.scheduler.rmi.export: false org.quartz.scheduler.rmi.proxy: false org.quartz.scheduler.wrapJobExecutionInUserTransaction: false org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount: 10 org.quartz.threadPool.threadPriority: 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true org.quartz.jobStore.misfireThreshold: 60000 org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

創建Job

實現唯一的方法execute(),方法中的代碼就是任務執行的內容。此處僅輸出字符串。

public class MyJob implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("假發在哪里買的");} }

在測試類main()方法中,把Job 進一步包裝成JobDetail。

必須要指定JobName 和groupName,兩個合起來是唯一標識符。

可以攜帶KV 的數據(JobDataMap),用于擴展屬性,在運行的時候可以從context獲取到。

JobDetail jobDetail = JobBuilder.newJob(MyJob1.class).withIdentity("job1", "group1").usingJobData("leon","2673").usingJobData("moon",5.21F).build();

創建Trigger

在測試類main()方法中,基于SimpleTrigger 定義了一個每2 秒鐘運行一次、不斷重復的Trigger:

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();

創建Scheduler

在測試類main()方法中,通過Factory 獲取調度器的實例,把JobDetail 和Trigger綁定,注冊到容器中。

Scheduler 先啟動后啟動無所謂,只要有Trigger 到達觸發條件,就會執行任務。

SchedulerFactory factory = new StdSchedulerFactory(); Scheduler scheduler = factory.getScheduler(); scheduler.scheduleJob(jobDetail, trigger); scheduler.start();

注意這里,調度器一定是單例的。

體系結構總結

JobDetail

我們創建一個實現Job 接口的類,使用JobBuilder 包裝成JobDetail,它可以攜帶KV 的數據。

Trigger

定義任務的觸發規律,Trigger,使用TriggerBuilder 來構建。

JobDetail 跟Trigger 是1:N 的關系。

思考:為什么要解耦?

Trigger 接口在Quartz 有4 個繼承的子接口:

子接口描述特點
SimpleTrigger簡單觸發器固定時刻或時間間隔,毫秒
CalendarIntervalTrigger基于日歷的觸發器比簡單觸發器更多時間單位,支持非固定時
間的觸發,例如一年可能365/366,一個月
可能28/29/30/31
DailyTimeIntervalTrigger基于日期的觸發器每天的某個時間段
CronTrigger基于Cron 表達式的觸發器?

代碼:standalone com.leon.trigger.TriggerDefine

SimpleTrigger

SimpleTrigger 可以定義固定時刻或者固定時間間隔的調度規則(精確到毫秒)。

例如:每天9 點鐘運行;每隔30 分鐘運行一次。

CalendarIntervalTrigger

CalendarIntervalTrigger 可以定義更多時間單位的調度需求,精確到秒。

好處是不需要去計算時間間隔,比如1 個小時等于多少毫秒。

例如每年、每個月、每周、每天、每小時、每分鐘、每秒。

每年的月數和每個月的天數不是固定的,這種情況也適用。

DailyTimeIntervalTrigger

每天的某個時間段內,以一定的時間間隔執行任務。

例如:每天早上9 點到晚上9 點,每隔半個小時執行一次,并且只在周一到周六執行。

CronTrigger

CronTirgger 可以定義基于Cron 表達式的調度規則,是最常用的觸發器類型。

Cron 表達式

位置時間域?特殊值
10-59, - * /
2分鐘0-59, - * /
3小時0-23, - * /
4日期1-31, - * ? / L W C
5月份1-12, - * /
6星期1-7, - * ? / L W C
7年份(可選)1-31, - * /

星號(*):可用在所有字段中,表示對應時間域的每一個時刻,例如,在分鐘字段時,表示“每分鐘”;

問號(?):該字符只在日期和星期字段中使用,它通常指定為“無意義的值”,相當于點位符;

減號(-):表達一個范圍,如在小時字段中使用“10-12”,則表示從10 到12 點,即10,11,12;

逗號(,):表達一個列表值,如在星期字段中使用“MON,WED,FRI”,則表示星期一,星期三和星期五;

斜杠(/):x/y 表達一個等步長序列,x 為起始值,y 為增量步長值。如在分鐘字段中使用0/15,則表示為0,15,30 和45 秒,而5/15 在分鐘字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;

L:該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個字段中意思不同。L 在日期字段中,表示這個月份的最后一天,如一月的31 號,非閏年二月的28 號;如果L 用在星期中,則表示星期六,等同于7。但是,如果L 出現在星期字段里,而且在前面有一個數值X,則表示“這個月的最后X 天”,例如,6L 表示該月的最后星期五;

W:該字符只能出現在日期字段里,是對前導日期的修飾,表示離該日期最近的工作日。例如15W 表示離該月15號最近的工作日,如果該月15 號是星期六,則匹配14 號星期五;如果15 日是星期日,則匹配16 號星期一;如果15號是星期二,那結果就是15 號星期二。但必須注意關聯的匹配日期不能夠跨月,如你指定1W,如果1 號是星期六,結果匹配的是3 號星期一,而非上個月最后的那天。W 字符串只能指定單一日期,而不能指定日期范圍;

LW 組合:在日期字段可以組合使用LW,它的意思是當月的最后一個工作日;

井號(#):該字符只能在星期字段中使用,表示當月某個工作日。如6#3 表示當月的第三個星期五(6 表示星期五,#3 表示當前的第三個),而4#5 表示當月的第五個星期三,假設當月沒有第五個星期三,忽略不觸發;

C:該字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是計劃所關聯的日期,如果日期沒有被關聯,則相當于日歷中所有日期。例如5C 在日期字段中就相當于日歷5 日以后的第一天。1C 在星期字段中相當于星期日后的第一天。

Cron 表達式對特殊字符的大小寫不敏感,對代表星期的縮寫英文大小寫也不敏感。

上面我們定義的都是在什么時間執行,但是我們有一些在什么時間不執行的需求,比如:理財周末和法定假日購買不計息;證券公司周末和法定假日休市。

是不是要把日期寫在數據庫中,然后讀取基于當前時間判斷呢?

基于Calendar 的排除規則

如果要在觸發器的基礎上,排除一些時間區間不執行任務,就要用到Quartz 的Calendar 類(注意不是JDK 的Calendar)。可以按年、月、周、日、特定日期、Cron表達式排除。

調用Trigger 的modifiedByCalendar() 添加到觸發器中, 并且調用調度器的addCalendar()方法注冊排除規則。

代碼示例:standalone 工程:com.leon.calendar.CalendarDemo

package com.leon.calendar;import com.leon.job.MyJob1; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.calendar.AnnualCalendar; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar;/*** @Author: qingshan* @Date: 2019/9/5 10:40* @Description: 咕泡學院,只為更好的你*/ public class CalendarDemo {public static void main(String[] args) throws Exception {SchedulerFactory sf = new StdSchedulerFactory();Scheduler scheduler = sf.getScheduler();scheduler.start();// 定義日歷AnnualCalendar holidays = new AnnualCalendar();// 排除咕泡日Calendar leonDay = (Calendar) new GregorianCalendar(2019, 8, 8);holidays.setDayExcluded(leonDay, true);// 排除中秋節Calendar midAutumn = new GregorianCalendar(2019, 9, 13);holidays.setDayExcluded(midAutumn, true);// 排除圣誕節Calendar christmas = new GregorianCalendar(2019, 12, 25);holidays.setDayExcluded(christmas, true);// 調度器添加日歷scheduler.addCalendar("holidays", holidays, false, false);JobDetail jobDetail = JobBuilder.newJob(MyJob1.class).withIdentity("job1", "group1").usingJobData("leon","青山 2673").build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().modifiedByCalendar("holidays").withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();Date firstRunTime = scheduler.scheduleJob(jobDetail, trigger);System.out.println(jobDetail.getKey() + " 第一次觸發: " + firstRunTime);} } Calendar 名稱用法
BaseCalendar為高級的Calendar 實現了基本的功能,實現了org.quartz.Calendar 接口
AnnualCalendar排除年中一天或多天
CronCalendar日歷的這種實現排除了由給定的CronExpression 表達的時間集合。例如,
您可以使用此日歷使用表達式“* * 0-7,18-23?* *”每天排除所有營業時
間(上午8 點至下午5 點)。如果CronTrigger 具有給定的cron 表達式并
且與具有相同表達式的CronCalendar 相關聯,則日歷將排除觸發器包含的
所有時間,并且它們將彼此抵消。
DailyCalendar您可以使用此日歷來排除營業時間(上午8 點- 5 點)每天。每個
DailyCalendar 僅允許指定單個時間范圍,并且該時間范圍可能不會跨越每
日邊界(即,您不能指定從上午8 點至凌晨5 點的時間范圍)。如果屬
性invertTimeRange 為false(默認),則時間范圍定義觸發器不允許觸發
的時間范圍。如果invertTimeRange 為true,則時間范圍被反轉- 也就是
排除在定義的時間范圍之外的所有時間。
HolidayCalendar特別的用于從Trigger 中排除節假日
MonthlyCalendar排除月份中的指定數天,例如,可用于排除每月的最后一天
WeeklyCalendar排除星期中的任意周幾,例如,可用于排除周末,默認周六和周日

Scheduler

調度器,是Quartz 的指揮官,由StdSchedulerFactory 產生。它是單例的。并且是Quartz 中最重要的API,默認是實現類是StdScheduler,里面包含了一個QuartzScheduler。QuartzScheduler 里面又包含了一個QuartzSchedulerThread。

Scheduler 中的方法主要分為三大類:

1)操作調度器本身,例如調度器的啟動start()、調度器的關閉shutdown()。

2)操作Trigger,例如pauseTriggers()、resumeTrigger()。

3)操作Job,例如scheduleJob()、unscheduleJob()、rescheduleJob()

這些方法非常重要,可以實現任務的動態調度。

Listener

我們有這么一種需求,在每個任務運行結束之后發送通知給運維管理員。那是不是要在每個任務的最后添加一行代碼呢?這種方式對原來的代碼造成了入侵,不利于維護。如果代碼不是寫在任務代碼的最后一行,怎么知道任務執行完了呢?或者說,怎么監測到任務的生命周期呢?

觀察者模式:定義對象間一種一對多的依賴關系,使得每當一個對象改變狀態,則所有依賴它的對象都會得到通知并自動更新。

Quartz 中提供了三種Listener,監聽Scheduler 的,監聽Trigger 的,監聽Job 的。只需要創建類實現相應的接口,并在Scheduler 上注冊Listener,便可實現對核心對象的監聽。

standalone 工程:com.leon.listener

MyJobListenerTest

MySchedulerListenerTest

MyTriggerListenerTest

package com.leon.listener;import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobListener;public class MyJobListener implements JobListener {public String getName() {String name = getClass().getSimpleName();System.out.println( "Method 111111 :"+ "獲取到監聽器名稱:"+name);return name;}public void jobToBeExecuted(JobExecutionContext context) {String jobName = context.getJobDetail().getKey().getName();System.out.println("Method 222222 :"+ jobName + " ——任務即將執行 ");}public void jobExecutionVetoed(JobExecutionContext context) {String jobName = context.getJobDetail().getKey().getName();System.out.println("Method 333333 :"+ jobName + " ——任務被否決 ");}public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {String jobName = context.getJobDetail().getKey().getName();System.out.println("Method 444444 :"+ jobName + " ——執行完畢 ");System.out.println("------------------");} } package com.leon.listener;import com.leon.job.MyJob1; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.matchers.EverythingMatcher;/*** 測試監聽器*/ public class MyJobListenerTest {public static void main(String[] args) throws SchedulerException {// JobDetailJobDetail jobDetail = JobBuilder.newJob(MyJob1.class).withIdentity("job1", "group1").build();// TriggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();// SchedulerFactorySchedulerFactory factory = new StdSchedulerFactory();// SchedulerScheduler scheduler = factory.getScheduler();scheduler.scheduleJob(jobDetail, trigger);// 創建并注冊一個全局的Job Listenerscheduler.getListenerManager().addJobListener(new MyJobListener(), EverythingMatcher.allJobs());scheduler.start();}} package com.leon.listener;import org.quartz.*;public class MySchedulerListener implements SchedulerListener {public void jobScheduled(Trigger trigger) {String jobName = trigger.getJobKey().getName();System.out.println( jobName + " has been scheduled");}public void jobUnscheduled(TriggerKey triggerKey) {System.out.println(triggerKey + " is being unscheduled");}public void triggerFinalized(Trigger trigger) {System.out.println("Trigger is finished for " + trigger.getJobKey().getName());}public void triggerPaused(TriggerKey triggerKey) {System.out.println(triggerKey + " is being paused");}public void triggersPaused(String triggerGroup) {System.out.println("trigger group "+triggerGroup + " is being paused");}public void triggerResumed(TriggerKey triggerKey) {System.out.println(triggerKey + " is being resumed");}public void triggersResumed(String triggerGroup) {System.out.println("trigger group "+triggerGroup + " is being resumed");}public void jobAdded(JobDetail jobDetail) {System.out.println(jobDetail.getKey()+" is added");}public void jobDeleted(JobKey jobKey) {System.out.println(jobKey+" is deleted");}public void jobPaused(JobKey jobKey) {System.out.println(jobKey+" is paused");}public void jobsPaused(String jobGroup) {System.out.println("job group "+jobGroup+" is paused");}public void jobResumed(JobKey jobKey) {System.out.println(jobKey+" is resumed");}public void jobsResumed(String jobGroup) {System.out.println("job group "+jobGroup+" is resumed");}public void schedulerError(String msg, SchedulerException cause) {System.out.println(msg + cause.getUnderlyingException().getStackTrace());}public void schedulerInStandbyMode() {System.out.println("scheduler is in standby mode");}public void schedulerStarted() {System.out.println("scheduler has been started");}public void schedulerStarting() {System.out.println("scheduler is being started");}public void schedulerShutdown() {System.out.println("scheduler has been shutdown");}public void schedulerShuttingdown() {System.out.println("scheduler is being shutdown");}public void schedulingDataCleared() {System.out.println("scheduler has cleared all data");} } package com.leon.listener;import com.leon.job.MyJob1; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.matchers.EverythingMatcher;/*** 測試監聽器*/ public class MySchedulerListenerTest {public static void main(String[] args) throws SchedulerException {// JobDetailJobDetail jobDetail = JobBuilder.newJob(MyJob1.class).withIdentity("job1", "group1").build();// TriggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();// SchedulerFactorySchedulerFactory factory = new StdSchedulerFactory();// SchedulerScheduler scheduler = factory.getScheduler();scheduler.scheduleJob(jobDetail, trigger);// 創建Scheduler Listenerscheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());scheduler.start();}} package com.leon.listener;import org.quartz.JobExecutionContext; import org.quartz.Trigger; import org.quartz.TriggerListener;public class MyTriggerListener implements TriggerListener {private String name;public MyTriggerListener(String name) {this.name = name;}public String getName() {return name;}// Trigger 被觸發,Job 上的 execute() 方法將要被執行時public void triggerFired(Trigger trigger, JobExecutionContext context) {String triggerName = trigger.getKey().getName();System.out.println("Method 11111 " + triggerName + " was fired");}// 在 Trigger 觸發后,Job 將要被執行時由 Scheduler 調用這個方法// 返回true時,這個任務不會被觸發public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {String triggerName = trigger.getKey().getName();System.out.println("Method 222222 " + triggerName + " was not vetoed");return false;}public void triggerMisfired(Trigger trigger) {String triggerName = trigger.getKey().getName();System.out.println("Method 333333 " + triggerName + " misfired");}public void triggerComplete(Trigger trigger, JobExecutionContext context,Trigger.CompletedExecutionInstruction triggerInstructionCode) {String triggerName = trigger.getKey().getName();System.out.println("Method 444444 " + triggerName + " is complete");System.out.println("------------");} } package com.leon.listener;import com.leon.job.MyJob1; import com.leon.listener.MyJobListener; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.matchers.EverythingMatcher; import org.quartz.impl.matchers.GroupMatcher; import org.quartz.impl.matchers.KeyMatcher;/*** 測試監聽器*/ public class MyTriggerListenerTest {public static void main(String[] args) throws SchedulerException {// JobDetailJobDetail jobDetail = JobBuilder.newJob(MyJob1.class).withIdentity("job1", "group1").build();// TriggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();// SchedulerFactorySchedulerFactory factory = new StdSchedulerFactory();// SchedulerScheduler scheduler = factory.getScheduler();scheduler.scheduleJob(jobDetail, trigger);// 創建并注冊一個全局的Trigger Listenerscheduler.getListenerManager().addTriggerListener(new MyTriggerListener("myListener1"), EverythingMatcher.allTriggers());// 創建并注冊一個局部的Trigger Listenerscheduler.getListenerManager().addTriggerListener(new MyTriggerListener("myListener2"), KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1", "gourp1")));// 創建并注冊一個特定組的Trigger ListenerGroupMatcher<TriggerKey> matcher = GroupMatcher.triggerGroupEquals("gourp1");scheduler.getListenerManager().addTriggerListener(new MyTriggerListener("myListener3"), matcher);scheduler.start();}}

JobListener

四個方法:

方法作用或執行實際
getName()返回JobListener 的名稱
jobToBeExecuted()Scheduler 在JobDetail 將要被執行時調用這個方法
jobExecutionVetoed()jobExecutionVetoed() Scheduler 在JobDetail 即將被執行,但又被TriggerListener 否決了時調用這個
方法
jobWasExecuted()Scheduler 在JobDetail 被執行之后調用這個方法

工具類:ListenerManager,用于添加、獲取、移除監聽器

工具類:Matcher,主要是基于groupName 和keyName 進行匹配。

TriggerListener

方法作用或執行實際
getName()返回監聽器的名稱
triggerFired()Trigger 被觸發,Job 上的execute() 方法將要被執行時,Scheduler 就調用這個
方法
vetoJobExecution()在Trigger 觸發后, Job 將要被執行時由Scheduler 調用這個方法。
TriggerListener 給了一個選擇去否決Job 的執行。假如這個方法返回true,這
個Job 將不會為此次Trigger 觸發而得到執行
triggerMisfired()Trigger 錯過觸發時調用
triggerComplete()Trigger 被觸發并且完成了Job 的執行時,Scheduler 調用這個方法

SchedulerListener

方法比較多,省略。

JobStore

問題:最多可以運行多少個任務(磁盤、內存、線程數)

Jobstore 用來存儲任務和觸發器相關的信息,例如所有任務的名稱、數量、狀態等等。Quartz 中有兩種存儲任務的方式,一種在在內存,一種是在數據庫。

RAMJobStore

Quartz 默認的JobStore 是RAMJobstore,也就是把任務和觸發器信息運行的信息存儲在內存中,用到了HashMap、TreeSet、HashSet 等等數據結構。

如果程序崩潰或重啟,所有存儲在內存中的數據都會丟失。所以我們需要把這些數據持久化到磁盤。

JDBCJobStore

JDBCJobStore 可以通過JDBC 接口,將任務運行數據保存在數據庫中。

JDBC 的實現方式有兩種,JobStoreSupport 類的兩個子類:

JobStoreTX:在獨立的程序中使用,自己管理事務,不參與外部事務。

JobStoreCMT:(Container Managed Transactions (CMT),如果需要容器管理事務時,使用它。

使用JDBCJobSotre 時,需要配置數據庫信息:

org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate # 使用quartz.properties,不使用默認配置 org.quartz.jobStore.useProperties:true #數據庫中quartz 表的表名前綴 org.quartz.jobStore.tablePrefix:QRTZ_ org.quartz.jobStore.dataSource:myDS #配置數據源 org.quartz.dataSource.myDS.driver:com.mysql.jdbc.Driver org.quartz.dataSource.myDS.URL:jdbc:mysql://localhost:3306/leon?useUnicode=true&characterEncoding=utf8 org.quartz.dataSource.myDS.user:root org.quartz.dataSource.myDS.password:123456 org.quartz.dataSource.myDS.validationQuery=select 0 from dual

問題來了?需要建什么表?表里面有什么字段?字段類型和長度是什么?

在官網的Downloads 鏈接中,提供了11 張表的建表語句:

quartz-2.2.3-distribution\quartz-2.2.3\docs\dbTables

2.3 的版本在這個路徑下:src\org\quartz\impl\jdbcjobstore

表名與作用:

表名作用
QRTZ_BLOB_TRIGGERSTrigger 作為Blob 類型存儲
QRTZ_CALENDARS存儲Quartz 的Calendar 信息
QRTZ_CRON_TRIGGERS存儲CronTrigger,包括Cron 表達式和時區信息
QRTZ_FIRED_TRIGGERS存儲與已觸發的Trigger 相關的狀態信息,以及相關Job 的執行信息
QRTZ_JOB_DETAILS存儲每一個已配置的Job 的詳細信息
QRTZ_LOCKS存儲程序的悲觀鎖的信息
QRTZ_PAUSED_TRIGGER_GRPS存儲已暫停的Trigger 組的信息
QRTZ_SCHEDULER_STATE存儲少量的有關Scheduler 的狀態信息,和別的Scheduler 實例
QRTZ_SIMPLE_TRIGGERS存儲SimpleTrigger 的信息,包括重復次數、間隔、以及已觸的次數
QRTZ_SIMPROP_TRIGGERS存儲CalendarIntervalTrigger 和DailyTimeIntervalTrigger 兩種類型的觸發器
QRTZ_TRIGGERS存儲已配置的Trigger 的信息

?

總結

以上是生活随笔為你收集整理的任务调度之Quartz1的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。