天天看點

[Quartz筆記]玩轉定時排程 簡介 Quartz的安裝 Hello World範例 API CronExpression表達式 參考資料

簡介

Quartz是什麼?

Quartz是一個特性豐富的、開源的作業排程架構。它可以內建到任何Java應用。

使用它,你可以非常輕松的實作定時任務的排程執行。

Quartz的應用場景

場景1:提醒和告警

場景2:監聽事務

場景3:定時作業

Quartz的安裝

安裝

1.可以直接在官網:

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

下載下傳jar包。

2.如果使用maven,可以在pom.xml中添加以下依賴jar包:

<dependency>

  <groupId>org.quartz-scheduler</groupId>

  <artifactId>quartz</artifactId>

  <version>2.2.1</version>

</dependency>

  <artifactId>quartz-jobs</artifactId>

源碼

Github位址:https://github.com/quartz-scheduler/quartz

Hello World範例

開始學習之前,慣例還是show一下Hello

World。

例:

1.先定義一個Job

import java.util.Date;

import org.quartz.Job;

import org.quartz.JobExecutionContext;

import org.quartz.JobExecutionException;

public class

HelloJob implements Job {

   @Override

   public void execute(JobExecutionContext context) throws JobExecutionException {

      System.out.println(String.format("Hello World! Time:%s", new

Date()));

   }

}

2.定義Job和Trigger去排程我們定義的HelloJob。

import org.quartz.JobBuilder;

import org.quartz.JobDetail;

import org.quartz.Scheduler;

import org.quartz.SchedulerFactory;

import org.quartz.SimpleScheduleBuilder;

import org.quartz.Trigger;

import org.quartz.TriggerBuilder;

import org.quartz.impl.StdSchedulerFactory;

import org.zp.tent.scheduler.demo.job.HelloJob;

/**

 * @Title HelloQuartz

 * @Description Quartz的Hello World執行個體

 * @Author zhangpeng

 * @Date 2016年7月6日

 */

HelloWorldDemo {

   public static void main(String[] args) {

      try {

        // 通過schedulerFactory擷取一個排程器

        SchedulerFactory schedulerfactory = new StdSchedulerFactory();

        Scheduler scheduler = schedulerfactory.getScheduler();

        // 建立jobDetail執行個體,綁定Job實作類

        JobDetail jobDetail =

JobBuilder.newJob(HelloJob.class).withIdentity("helloJob", "jobGroup1").build();

        // 定義排程觸發規則,本例中使用SimpleScheduleBuilder建立了一個5s執行一次的觸發器

        Trigger trigger =

TriggerBuilder.newTrigger().withIdentity("myTrigger", "triggerGroup1").startNow()

              .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever())

              .build();

        // 把作業和觸發器注冊到任務排程中

        scheduler.scheduleJob(jobDetail, trigger);

        // 啟動排程

        scheduler.start();

        // 60s後關閉

        Thread.sleep(1000 * 30);

        scheduler.shutdown();

        System.out.println("排程任務結束");

      } catch

(Exception e) {

        e.printStackTrace();

      }

好了,運作一下試試吧。

API

核心API

Scheduler接口:

作用:Scheduler接口是Quartz最核心的接口。Scheduler維護着JobDetail和Trigger的注冊資訊。一旦注冊成功,Scheduler負責執行和Job關聯的觸發器。

一個Scheduler執行個體可以視為一個排程作業容器。可以通過start和shutdown方法來控制它的生命周期。

// 通過schedulerFactory擷取一個排程器

SchedulerFactory

schedulerfactory = new StdSchedulerFactory();

Scheduler

scheduler = schedulerfactory.getScheduler();

// 啟動

scheduler.start();

//關閉

scheduler.shutdown();

Job接口

作用:開發者實作該接口定義需要執行的作業。JobExecutionContext類提供排程上下文的各種資訊。

實作Job接口的類還可以使用注解進行修飾。

@DisallowConcurrentExecution:此注解表示不允許這個Job并發執行

@PersistJobDataAfterExecution:此注解表示當這個Job的execute方法執行成功後,更新并存儲它所持有的JobDetail屬性中JobDataMap。如果使用這個注解,強烈建議也使用@DisallowConcurrentExecution,因為并發執行過程中,JobDataMap有可能會發生沖突。

public class xxxJob implements Job {

      …

JobDetail接口

作用:用于定義Job執行個體。

JobDetail有兩個boolean屬性。

isDurable:如果設為false,則對應的Job一旦沒有關聯的觸發器,就會被Scheduler自動删除。

requestsRecovery:如果設為true,當Job執行中遇到硬中斷(例如運作崩潰、機器斷電等),Scheduler會重新執行。這種情況下,JobExecutionContext.isRecovering()會傳回ture。

JobBuilder類

作用:用于定義、建構JobDetail執行個體。

// 建立jobDetail執行個體,綁定Job實作類

JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("helloJob", "jobGroup1").build();

Trigger接口

作用:定義Job執行的觸發規則。

Quartz中有多種觸發器,最常用的是SimpleTrigger 和 CronTrigger。

SimpleTrigger一般用于隻執行一次或在指定時間執行的作業;CronTrigger一般用于周期性執行(例如,每日執行、每周執行)的作業,需要按照指定的時間表達式規則設定排程時間。

Priority:這個屬性表示Trigger的權重。當兩個Trigger觸發時間相同時,權重大的那個先執行。Quartz預設的權重值為5。

Misfire Instruction:在Trigger接口中可以設定錯過觸發處理機制。就是說在指定觸發的時間點由于某種原因錯過執行的時機了,這時如何去處理。Quartz提供了多種政策,這裡不詳述,有興趣的可以參考官方文檔。

Job和Trigger的關系

多個Job可以依賴于一個Trigger;多個Trigger也可以關聯一個Job。

但是,從最佳實踐來看,最好讓Job和Trigger保持一對多的關系,這樣更便于管理。

TriggerBuilder類

作用:用于定義、建構Trigger執行個體。

下面兩種方式是一樣的效果,都是建立一個每5s執行一次的觸發器

// 定義排程觸發規則, SimpleScheduleBuilder方式

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "triggerGroup1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();

// 定義排程觸發規則, CronScheduleBuilder方式

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "triggerGroup1").startNow().withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();

第二種觸發器建構方式中使用了形如"0/5 * * * * ?"的CronExpression表達式來建立觸發器規則。這裡不在細說,在下文的CronExpression表達式一節再詳述。

JobDataMap

JobDetail接口中持有JobDataMap類。開發者可以将作業執行時需要的參數或對象填入這個類中。

填入資料和擷取資料的方式很類似Json。

先定義一個Job

WithJobDataMapJob implements Job {

      // 基本資訊

      JobKey jobKey = context.getJobDetail().getKey();

      TriggerKey triggerKey

= context.getTrigger().getKey();

      // 擷取JobDataMap的方式:如果是基本類型,JobDataMap提供了多種get方法;如果是引用類型,可以直接get,然後進行強制轉換

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

      Student student =

(Student) dataMap.get("student");

      List<String> interests = (List<String>) dataMap.get("interests");

      String word = dataMap.getString("word");

      System.out.println(String.format("[JobKey:%s][TriggerKey:%s] of

DumbJob print info:", jobKey, triggerKey));

      System.out.println(String.format("[Student]name:%s, age:%d,

sex:%s", student.getName(),

student.getAge(),

           student.getSex()));

      StringBuilder interestsStr

= new StringBuilder();

      for (String

item : interests) {

        interestsStr.append(item + "

");

      System.out.println("His interests ars: " + interestsStr.toString());

      System.out.println("He want to say: " + word);

      System.out.println("===================================");

用戶端代碼:

public static void main(String[] args) {

JobBuilder.newJob(WithJobDataMapJob.class).withIdentity("myJob", "group1").build();

        // 使用JobDataMap填入想要攜帶的特殊資訊。可以填入基本資料類型、字元串、集合,甚至是一個對象。填入方式很類似JSON

        Student student = new Student("Jack", 20, "male");

        List<String> interests = new ArrayList<String>();

        interests.add("dancing");

        interests.add("singing");

        interests.add("swimming");

        String word = "Hello World!";

        JobDataMap map = jobDetail.getJobDataMap();

        map.put("student", student);

        map.put("interests", interests);

        map.put("word", word);

其他常見API

JobKey 和 TriggerKey

在Quartz中,可以分别通過JobKey和TriggerKey來唯一地識别一個Job或一個Trigger。

這兩個Key都有兩個關鍵屬性:name和group。

CronExpression表達式

還記得上文中展示的使用CronScheduleBuilder方式建構觸發器時的例子嗎?在這個例子中,我們使用的表達式字元串"0/5

* * * * ?"是什麼意思呢?閱讀本節後,你就會了解了。

表達式規則

一個cron表達式有至少6個(也可能7個)有空格分隔的時間元素。

CronTrigger配置完整格式為: [秒] [分] [小時] [日] [月] [周] [年]

參數設定規則見下表

字段     允許值 允許的特殊字元
0-59 , - * /
小時 0-23
日期 1-31 , - * ? / L W
月份 1-12 或者 JAN-DEC
星期 1-7 或者 SUN-SAT , - * ? / L #
年(可選) 留白, 1970-2099

表 cronExpression表達式參數

符号說明

通配符*

表示所有值。

例如:在分的字段上設定 "*",表示每一分鐘都會觸發。

通配符?

表示不指定值。使用的場景為不需要關心目前設定這個字段的值。

例如:要在每月的10号觸發一個操作,但不關心是周幾,是以需要周位置的那個字段設定為"?"

具體設定為 0 0 0 10 * ?

通配符-

表示區間。

例如在小時上設定 "10-12",表示 10,11,12點都會觸發。

通配符,

表示指定多個值。

例如在周字段上設定 "MON,WED,FRI" 表示周一,周三和周五觸發

通配符/

用于遞增觸發。如在秒上面設定"5/15" 表示從5秒開始,每增15秒觸發(5,20,35,50)。在月字段上設定'1/3'所示每月1号開始,每隔三天觸發一次。

通配符L

表示最後的意思。

例如在日字段設定上,表示當月的最後一天(依據目前月份,如果是二月還會依據是否是潤年[leap]), 在周字段上表示星期六,相當于"7"或"SAT"。如果在"L"前加上數字,則表示該資料的最後一個。例如在周字段上設定"6L"這樣的格式,則表示“本月最後一個星期五"

通配符W

表示離指定日期的最近那個工作日(周一至周五)。

例如在日字段上設定"15W",表示離每月15号最近的那個工作日觸發。如果15号正好是周六,則找最近的周五(14号)觸發, 如果15号是周未,則找最近的下周一(16号)觸發。如果15号正好在工作日(周一至周五),則就在該天觸發。如果指定格式為 "1W",它則表示每月1号往後最近的工作日觸發。如果1号正是周六,則将在3号下周一觸發。(注,"W"前隻能設定具體的數字,不允許區間"-")。

小提示:'L'和

'W'可以一組合使用。如果在日字段上設定"LW",則表示在本月的最後一個工作日觸發;周字段的設定,若使用英文字母是不區分大小寫的,即MON與mon相同。

通配符#

表示每月的第幾個周幾。

例如在周字段上設定"6#3"表示在每月的第三個周六。注意如果指定"#5",正好第五周沒有周六,則不會觸發該配置(用在母親節和父親節再合适不過了)。

注:表中月份一行的JAN-DEC,是指一月到十二月的英文縮寫;星期一行的SUN-SAT,是指星期天到星期六的英文縮寫。

使用表達式的案例

案例 意義
"0 0 12 * * ?" 每天中午12點觸發
"0 15 10 ? * *" 每天上午10:15觸發
"0 15 10 * * ?"
"0 15 10 * * ? *"
"0 15 10 * * ? 2005" 2005年的每天上午10:15 觸發
"0 * 14 * * ?" 在每天下午2點到下午2:59期間的每1分鐘觸發
"0 0/5 14 * * ?" 在每天下午2點到下午2:55期間的每5分鐘觸發
"0 0/5 14,18 * * ?" 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發
"0 0-5 14 * * ?" 在每天下午2點到下午2:05期間的每1分鐘觸發
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2: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 2002-2005" 2002年至2005年的每月的最後一個星期五上午10:15觸發
"0 15 10 ? * 6#3" 每月的第三個星期五上午10:15觸發

參考資料

官方文檔:

http://www.quartz-scheduler.org/documentation/

官方2.2版本教程:

http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/