[Quartz筆記]玩轉定時調度

簡介

Quartz是什麼?

Quartz是一個特性豐富的、開源的做業調度框架。它能夠集成到任何Java應用。 java

使用它,你能夠很是輕鬆的實現定時任務的調度執行。 git

 

Quartz的應用場景

場景1:提醒和告警 github

場景2:監聽事務 併發

場景3:定時做業 app

 

Quartz的安裝

安裝

1.能夠直接在官網:http://www.quartz-scheduler.org/ 下載jar包。 框架

2.若是使用maven,能夠在pom.xml中添加如下依賴jar包: maven

<dependency> ide

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

  <artifactId>quartz</artifactId> ui

  <version>2.2.1</version>

</dependency>

<dependency>

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

  <artifactId>quartz-jobs</artifactId>

  <version>2.2.1</version>

</dependency>

 

源碼

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.定義JobTrigger去調度咱們定義的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 QuartzHello World實例

 * @Author zhangpeng

 * @Date 201676

 */

public class HelloWorldDemo {

   public static void main(String[] args) {

      try {

        // 經過schedulerFactory獲取一個調度器

        SchedulerFactory schedulerfactory = new StdSchedulerFactory();

 

        // 經過schedulerFactory獲取一個調度器

        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維護着JobDetailTrigger的註冊信息。一旦註冊成功,Scheduler負責執行和Job關聯的觸發器。

一個Scheduler實例能夠視爲一個調度做業容器。能夠經過startshutdown方法來控制它的生命週期。

例:

// 經過schedulerFactory獲取一個調度器

SchedulerFactory schedulerfactory = new StdSchedulerFactory();

 

// 經過schedulerFactory獲取一個調度器

Scheduler scheduler = schedulerfactory.getScheduler();

 

// 啓動

scheduler.start();

 

//關閉

scheduler.shutdown();

 

Job接口

做用:開發者實現該接口定義須要執行的做業。JobExecutionContext類提供調度上下文的各類信息。

實現Job接口的類還可使用註解進行修飾。

@DisallowConcurrentExecution:此註解表示不容許這個Job併發執行

@PersistJobDataAfterExecution:此註解表示當這個Jobexecute方法執行成功後,更新並存儲它所持有的JobDetail屬性中JobDataMap。若是使用這個註解,強烈建議也使用@DisallowConcurrentExecution,由於併發執行過程當中,JobDataMap有可能會發生衝突。

例:

public class xxxJob implements Job {

   @Override

   public void execute(JobExecutionContext context) throws JobExecutionException {

      …

   }

}

 

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提供了多種策略,這裏不詳述,有興趣的能夠參考官方文檔。

 

 

JobTrigger的關係

多個Job能夠依賴於一個Trigger;多個Trigger也能夠關聯一個Job

可是,從最佳實踐來看,最好讓JobTrigger保持一對多的關係,這樣更便於管理。

 

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

public class WithJobDataMapJob implements Job {

   public void execute(JobExecutionContext context) throws JobExecutionException {

      // 基本信息

      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) {

      try {

        // 經過schedulerFactory獲取一個調度器

        SchedulerFactory schedulerfactory = new StdSchedulerFactory();

 

        // 經過schedulerFactory獲取一個調度器

        Scheduler scheduler = schedulerfactory.getScheduler();

 

        // 建立jobDetail實例,綁定Job實現類

        JobDetail jobDetail = 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);

 

        // 定義調度觸發規則,本例中使用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

JobKey TriggerKey

Quartz中,能夠分別經過JobKeyTriggerKey來惟一地識別一個Job或一個Trigger

這兩個Key都有兩個關鍵屬性:namegroup

 

CronExpression表達式

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

還記得上文中展現的使用CronScheduleBuilder方式構建觸發器時的例子嗎?在這個例子中,咱們使用的表達式字符串"0/5 * * * * ?"是什麼意思呢?閱讀本節後,你就會了解了。

 

表達式規則

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

CronTrigger配置完整格式爲: [] [] [小時] [] [] [] []

參數設置規則見下表

字段    

容許值

容許的特殊字符

0-59

, - * /

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",則表示在本月的最後一個工做日觸發;周字段的設置,若使用英文字母是不區分大小寫的,即MONmon相同。

 

通配符#

表示每個月的第幾個周幾。

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

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

 

使用表達式的案例

案例

意義

"0 0 12 * * ?"

天天中午12點觸發

"0 15 10 ? * *"

天天上午10:15觸發

"0 15 10 * * ?"

天天上午10:15觸發

"0 15 10 * * ? *"

天天上午10:15觸發

"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:102: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/

相關文章
相關標籤/搜索