[Quartz筆記]玩轉定時調度


簡介

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>

<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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM