一、Quartz可以用來做什麼
Quartz是一個強大任務調度框架,我工作時候會在這些情況下使用到quartz框架,當然還有很多的應用場景,在這裏只列舉2個實際用到的
- 用緩存的時候,每天十二點定時對內存中的全量數據進行一次更新。
-
人事系統會在每天早晨8點給有待辦的人員自動發送Email提醒
在我們實際的項目中,當Job過多的時候,肯定不能人工去操作,這時候就需要一個任務調度框架,幫我們自動去執行這些程序。那麼該如何實現這個功能呢?
(1)首先我們需要定義實現一個定時功能的接口,我們可以稱之爲Task(或Job),如定時發送郵件的task(Job),重啓機器的task(Job),優惠券到期發送短信提醒的task(Job),實現接口如下:
(2)有了任務之後,還需要一個能夠實現觸發任務去執行的觸發器,觸發器Trigger最基本的功能是指定Job的執行時間,執行間隔,運行次數等。
(3)有了Job和Trigger後,怎麼樣將兩者結合起來呢?即怎樣指定Trigger去執行指定的Job呢?這時需要一個Schedule,來負責這個功能的實現。
上面三個部分就是Quartz的基本組成部分:
- 調度器:Scheduler
- 任務:JobDetail
- 觸發器:Trigger,包括SimpleTrigger和CronTrigger
二、使用Quartz之前的準備
1.建立一個Maven項目
2.引入quartz的依賴
使用quartz,我們僅僅需要在maven的pom文件中添加依賴即可。我使用的是現在最新的一個版本2.3.0,大家可以在maven的倉庫獲取到最新的版本依賴,地址:http://mvnrepository.com/artifact/org.quartz-scheduler/quartz
但然也可以使用這個2.3.0的依賴,下面的例子都是使用此依賴並實現了效果。
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
三、編寫第一個Quartz任務案例 - 每隔2秒鐘打印一次HelloQuartz
1.創建一個類 HelloJob.java,這個類是編寫我們的具體要實現任務(打印Hello Quartz)
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloJob implements Job{
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//打印當前的執行時間 例如 2019-09-06 00:00:00
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("現在的時間是:"+ sf.format(date));
//具體的業務邏輯
System.out.println("Hello Quartz");
}
}
2.創建一個類HelloScheduler.java,這個是具體觸發我們的任務
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//創建一個jobDetail的實例,將該實例與HelloJob Class綁定
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("myJob").build();
//創建一個Trigger觸發器的實例,定義該job立即執行,並且每2秒執行一次,一直執行
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();
//創建schedule實例
StdSchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail,trigger);
}
}
3、運行程序,可以看見如下效果,表明任務執行成功了
四、第二個案例 - 每日的9點40分觸發任務打印HelloQuartz
與上一個的簡單案例的區別在於,SimpleTrigger/CronTrigger. 簡單的定時任務,可以採用SimpleTrigger,複雜的任務一般採用CronTrigger.cronTrigger不僅可以設定單的觸發時間表,更可以設定非常複雜的觸發時間表。 CronTrigger 是基於 Unix類似於 cron 表達式,如果對cron表達式比較熟悉,那麼學習起來經非常簡單. 即使對cron表達式不熟悉,花一會兒的功夫也可以學會。(在工作中我們直接使用網上的在線生成表達式即可又快又準確)生成地址:http://cron.qqe2.com/
先上代碼,然後介紹一下cron表達式生成規則。
1.編寫任務類 HelloJob.java,具體情況編寫具體內容,如生成報表,發送郵件
public class HelloJob implements Job{
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//打印當前的執行時間 例如 2017-11-22 00:00:00
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("現在的時間是:"+ sf.format(date));
//具體的業務邏輯
System.out.println("開始生成任務報表 或 開始發送郵件");
}
}
2.編寫任務觸發類 CronScheduler.java
public class CronScheduler {
public static void main(String[] args) throws SchedulerException, InterruptedException {
//jobDetail
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("cronJob").build();
//cronTrigger
//每日的9點40觸發任務
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("cronTrigger").withSchedule(CronScheduleBuilder.cronSchedule("0 40 9 * * ? ")).build();
//1.每日10點15分觸發 0 15 10 ?* *
//2.每天下午的2點到2點59分(正點開始,隔5分觸發) 0 0/5 14 * * ?
//3.從週一到週五每天的上午10點15觸發 0 15 10 ? MON-FRI
//4.每月的第三週的星期五上午10點15觸發 0 15 10 ? * 6#3
//5.2016到2017年每月最後一週的星期五的10點15分觸發 0 15 10 ? * 6L 2016-2017
//Scheduler實例
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = stdSchedulerFactory.getScheduler();
scheduler.start();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
}
3.觸發的效果
五、cron表達式編寫規則
1. Quartz Cron 表達式支持7個域 ,分別是秒/分/時/日/月/周/年.期中年是非必須項.如下圖
名稱 | 是否必須 | 允許值 | 特殊字符 |
---|---|---|---|
秒 | 是 | 0-59 | , - * / |
分 | 是 | 0-59 | , - * / |
時 | 是 | 0-23 | , - * / |
日 | 是 | 1-31 | , - * ? / L W C |
月 | 是 | 1-12 或 JAN-DEC | , - * / |
周 | 是 | 1-7 或 SUN-SAT | , - * ? / L C # |
年 | 否 | 空 或 1970-2099 | , - * / |
注意在cron表達式中不區分大小寫.
星號(*):可用在所有字段中,表示對應時間域的每一個時刻,例如, 在分鐘字段時,表示“每分鐘”;
問號(?):該字符只在日期和星期字段中使用,它通常指定爲“無意義的值”,相當於點位符;
減號(-):表達一個範圍,如在小時字段中使用“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表達式對特殊字符的大小寫不敏感,對代表星期的縮寫英文大小寫也不敏感。
2.官方的一些案例
表示式 | 說明 |
---|---|
0 0 12 * * ? | 每天12點運行 |
0 15 10 ? * * | 每天10:15運行 |
0 15 10 * * ? | 每天10:15運行 |
0 15 10 * * ? * | 每天10:15運行 |
0 15 10 * * ? 2008 | 在2008年的每天10:15運行 |
0 * 14 * * ? | 每天14點到15點之間每分鐘運行一次,開始於14:00,結束於14:59。 |
0 0/5 14 * * ? | 每天14點到15點每5分鐘運行一次,開始於14:00,結束於14:55。 |
0 0/5 14,18 * * ? | 每天14點到15點每5分鐘運行一次,此外每天18點到19點每5鍾也運行一次。 |
0 0-5 14 * * ? | 每天14:00點到14:05,每分鐘運行一次。 |
0 10,44 14 ? 3 WED | 3月每週三的14:10分到14:44,每分鐘運行一次。 |
0 15 10 ? * MON-FRI | 每週一,二,三,四,五的10:15分運行。 |
0 15 10 15 * ? | 每月15日10:15分運行。 |
0 15 10 L * ? | 每月最後一天10:15分運行。 |
0 15 10 ? * 6L | 每月最後一個星期五10:15分運行。 |
0 15 10 ? * 6L 2007-2009 | 在2007,2008,2009年每個月的最後一個星期五的10:15分運行。 |
0 15 10 ? * 6#3 | 每月第三個星期五的10:15分運行。 |
以上就可以實現大部分的業務的需求了,想要進一步學習可以到https://www.cnblogs.com/zhanghaoliang/p/7886110.html對Quartz的API進一步學習。