Quartz初探

守望碼靈發表於2020-11-08

目錄

 

Quartz執行環境

Quartz設計模式

Quartz學習的核心概念

Quartz的幾個常用API

入門案例

Job和JobDetail介紹

JobExecutionContext介紹

JobDataMap介紹

有狀態的Job和無狀態的Job


Quartz執行環境

  • Quartz可以執行嵌入在另一個獨立式應用程式
  • Quartz可以在應用程式伺服器(或servlet容器)內被例項化,並且參與事務
  • Quartz可以作為一個獨立的程式執行(其自己的java虛擬機器內),可以通過RMI使用
  • Quartz可以被例項化,作為獨立的專案叢集(負載平衡和故障轉移功能),用於作業的排程

Quartz設計模式

  • Builder模式
  • Factory模式
  • 元件模式
  • 鏈式模式

Quartz學習的核心概念

  • 任務job:想實現的任務類,每一個job必須實現org.quartz.job介面,且只需要實現介面定義的execute()方法.
  • 觸發器Trigger:執行任務的觸發器,比如你每天想定時3點傳送一份郵件,Trigger將會設定3點進行執行該任務。Trigger主要包含兩種SimpleTriggerCronTrigger兩種.
  • 排程器Scheduler:為任務的排程器,它會將任務job及trigger整合起來,負責基於Trigger設定的時間來執行Job.

Quartz的幾個常用API

Scheduler用於與排程程式互動的主程式介面

Scheduler排程程式-任務計劃執行表,只有安排進執行計劃的任務job(通過scheduler.schdeuleJob方法安排進執行計劃),當它預先定義的執行時間到了的時候(任務觸發trigger)

Job我們預先定義的希望在未來時間能被排程程式執行的任務類,我們可以自定義。

JobDetail使用JobDetail來定義定時任務的例項,jobDetail例項是通過jobBuilder類建立的

JobDataMap可以包含不限量的(序列化的)資料物件,在job例項執行的時候,可以使用其中的資料;JobDataMap是Java Map介面的一個實現,額外增加了一些便於存取基本型別的資料方法

Trigger觸發器,Trigger物件是用來觸發執行Job的。當排程一個job時,我們例項一個觸發器然後調整它的屬性來滿足job執行的條件。表明任務在什麼時候會執行。定義了一個已經被安排的任務將會在什麼時候執行的時間條件,比如每2秒執行一次。

JobBuilder:用於宣告一個任務例項,也可以定義關於該任務的詳情比如任務名、組名等,這個宣告的例項將會作為一個實際執行的任務。

TriggerBuilder觸發器建立器,使用者建立觸發器trigger例項

JobListener、TriggerListener、SchedulerListener監聽器,用於對元件的監聽

入門案例

1. 建立Maven專案,在pom中新增Quartz的依賴包

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

2.建立一個HelloJob類實現Job介面並重寫裡面的execute方法

package quartz.job;

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 {
        //輸出當前時間
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);
        System.out.println("正在進行資料庫的備份工作,備份資料庫的時間是:" + dateString);
    }
}

3. 建立HelloScheduler的主類

package quartz.main;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import quartz.job.HelloJob;

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        //1: 排程器(Schduler),從工廠中獲取排程的例項(預設:例項化new StdSchdulerFactory())
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //2: 任務例項(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//載入任務類,與HelloJob(實現Job介面)完成繫結
                .withIdentity("job1","group1")//引數1: 任務的名稱(唯一例項); 引數2:任務組的名稱
                .build();
        //3: 觸發器(Trigger)
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") //引數1: 觸發器的名稱(唯一例項); 引數2:  觸發器組的名稱
                .startNow()//馬上啟動這個觸發器
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).withRepeatCount(5))
                .build();

        //讓排程器關聯任務和觸發器,讓任務按照觸發器定義的條件執行任務
        scheduler.scheduleJob(jobDetail, trigger);

        //啟動
        scheduler.start();

    }
}

Job和JobDetail介紹

  • job:工作任務排程的介面,任務類需要實現該介面。該介面中定義execute方法,類似JDK提供的TImeTask類的run方法。在裡面編寫任務執行的業務邏輯
  • job例項在Quartz的生命週期:每次排程器執行job時,它在呼叫execure方法前會建立一個新的job例項,當呼叫完成後,關聯的job物件例項會被釋放,釋放的例項會被垃圾回收機制回收
  • jobDetail:jobDetail為job提供了許多設定屬性,以及jobDetaMap成員變數屬性,它用來儲存特定的job例項的狀態資訊,排程器需要藉助jobDetail物件來新增job例項。
  • jobDetail重要屬性: name、group、jobClass、jobDataMap
        System.out.println("名稱:" + jobDetail.getKey().getName());
        System.out.println("組的名稱:" + jobDetail.getKey().getGroup()); //如果沒有指定組名:DEFAULT
        System.out.println("任務類:" + jobDetail.getJobClass().getName());

JobExecutionContext介紹

  • 當Scheduler呼叫一個job,就會將JobExecutionContext傳遞給Job的execute()方法
  • Job能通過JobExecutionContext物件訪問到Quartz執行時候的環境以及job本身的明細資料

JobDataMap介紹

  • (1)使用Map獲取
  • 在進行任務排程時,JobDataMap儲存在JobExecutionContext中,非常方便獲取
  • JobDataMap可以用來裝載任何可序列化的資料物件,當job例項物件被執行時這些引數物件會傳遞給它
  • JobDataMap實現了JDK的Map介面,並且新增了非常方便的方法用來存取基本資料型別

比如:在JobDetail和Trigger中都傳遞引數,然後再job中獲取對應的引數

HelloScheduler.java中傳遞引數

        //2: 任務例項(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//載入任務類,與HelloJob(實現Job介面)完成繫結
                .withIdentity("job1","group1")//引數1: 任務的名稱(唯一例項); 引數2:任務組的名稱
                .usingJobData("message", "列印日誌")
                .build();
        //3: 觸發器(Trigger)
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") //引數1: 觸發器的名稱(唯一例項); 引數2:  觸發器組的名稱
                .startNow()//馬上啟動這個觸發器
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).withRepeatCount(5))
                .usingJobData("message", "simple觸發器")
                .build();

job中獲取傳遞過來的引數值

public class HelloJob implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //輸出當前時間
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);
        System.out.println("正在進行資料庫的備份工作,備份資料庫的時間是:" + dateString);

        //從JobDetail物件中獲取jobDataMap的資料
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        String jobDataMessage = jobDataMap.getString("message");
        System.out.println("任務資料的引數值" + jobDataMessage);

        //從Trigger物件中獲取jobDataMap的資料
        JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();
        String triggerDataMessage = triggerDataMap.getString("message");
        System.out.println("觸發器資料的引數值" + triggerDataMessage);

    }
}

 在任務執行過程中獲取其他比較重要的值

        //獲取其他任務
        System.out.println("當前任務的執行時間:" + jobExecutionContext.getFireTime());
        System.out.println("下一次任務的執行時間:" + jobExecutionContext.getNextFireTime());

(2) Job實現類中新增setter方法對應JobDataMap的鍵值,Quartz框架預設的JobFactory實現類在初始化job例項物件時會自動地呼叫這些setter方法。

    private String message;
    public void setMessage(String message){
        this.message = message;
    }

這裡注意:如果遇到同名的key,Trigger中的.usingJobData("message","simple觸發器")會覆蓋jobDetail中的usingJobData("message", "列印日誌");

有狀態的Job和無狀態的Job

@PersistDataAfterExecution註解的使用

有狀態的job可以理解為多次job呼叫期間可以持有一些狀態資訊,這些狀態資訊儲存在jobDataMap中,而預設的無狀態job每次呼叫時都會建立一個新的JobDataMap

(1)修改HelloScheduler.新增.usingJobData("count", 0), 表示計數器

        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//載入任務類,與HelloJob(實現Job介面)完成繫結
                .withIdentity("job1","group1")//引數1: 任務的名稱(唯一例項); 引數2:任務組的名稱
                .usingJobData("message", "列印日誌")
                .usingJobData("count", 0)
                .build();

(2)修改Hello.java-新增count的setting和getting方法

    private String message;
    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }

    public Integer getCount() {
        return count;
    }
    /*省略一塊邏輯*/
    //在execute()方法中
    ++count;
    jobExecutionContext.getJobDetail().getJobDataMap().put("count", count);

結果顯示每次輸出的值都為0

在HelloJob上新增@PersistDataAfterExecution,多次呼叫,會對Job進行持久化,儲存一些資料的資訊

import java.util.Date;
@PersistJobDataAfterExecution
public class HelloJob implements Job {
    private String message;
    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }

執行結果為:count的值變成有狀態的了,被不斷地進行累加

 

相關文章