Java定時任務調度框架Quartz入門詳解案例


一、什么是Quartz

Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,完全由Java開發,可以用來執行定時任務,類似於java.util.Timer。但是相較於Timer, Quartz增加了很多功能:

  • 持久性作業 - 就是保持調度定時的狀態;
  • 作業管理 - 對調度作業進行有效的管理;

拿火車票購票來說,當你下單后,后台就會插入一條待支付的task(job),一般是30分鍾,超過30min后就會執行這個job,去判斷你是否支付,未支付就會取消此次訂單;當你支付完成之后,后台拿到支付回調后就會再插入一條待消費的task(job),Job觸發日期為火車票上的出發日期,超過這個時間就會執行這個job,判斷是否使用等。

二、Quartz核心概念

1.任務/作業(Task/Job)

位於org.quartz.Job的接口,是quartz中的核心任務接口,要實現自定義的定時任務(就是我們要執行的業務動作/作業)只需要實現此接口。

這里寫圖片描述

2.觸發器(Trigger)

位於org.quartz.Trigger,觸發器用來告訴調度程序作業什么時候觸發,也就是我們要設置任務觸發的條件。quartz提供了5種觸發器類型,但兩個最常用的SimpleTrigger和CronTrigger。

五種類型的Trigger(觸發器):
SimpleTrigger,CronTirgger,DateIntervalTrigger,NthIncludedDayTrigger和Calendar。

這里寫圖片描述

3.調度器(Schedule)

來自org.quartz.Schedule是Quartz Scheduler的主要接口,代表一個獨立運行容器。調度程序維護JobDetails和觸發器的注冊表。 一旦注冊,調度器負責執行作業,當他們的相關聯的觸發器觸發時(當他們的預定時間到達時)。不難看出功能就是將任務job與觸發器Trigger作業結合起來。

img

4.任務執行時上下文(JobExecutionContext)

位於org.quartz.JobExecutionContext的類,是任務在執行時quartz注入的對象,用於保存任務的詳細信息(比如觸發器,調度器,工作詳情,任務入參等),我們可以通過此對象得到運行時的任務數據,也可以接受動態參數。

主要有以下方法:

image-20210104144243980

5.任務詳情(JobDetail)

位於org.quartz.JobDetail,用來綁定job,為job提供一些屬性:

  • name:唯一標識
  • group:分組標識
  • jobClass:具體任務
  • jobDataMap:任務入參

為什么設計成JobDetail + Job,不直接使用Job?

JobDetail定義的是任務數據,而真正的執行邏輯是在Job中。
這是因為任務是有可能並發執行,如果Scheduler直接使用Job,就會存在對同一個Job實例並發訪問的問題。而JobDetail & Job 方式,Sheduler每次執行,都會根據JobDetail創建一個新的Job實例,這樣就可以規避並發訪問的問題。

三、案例demo實現

1.定義自定義任務,繼承job接口

public class MyJob implements Job {

    private final Logger log = LoggerFactory.getLogger(MyJob.class);

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        log.error("定時任務:發送一次消息,時間={"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))+
                "}");
        log.error("請求參數:{name="+context..getJobDetail().getJobDataMap().get("name").toString()+",sign="+context.getJobDetail().getJobDataMap().get("sign").toString()+"}");
    }
}

2.創建demo

public class Demo {

    public static void main(String[] args) throws SchedulerException {
        //1.初始化調度器工廠
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        //2.獲取調度器
        Scheduler scheduler = schedulerFactory.getScheduler();

        //3.創建任務實例
        JobDetail jobDetail = newJob(MyJob.class)//一個靜態builder方法
                .withDescription("這是我的入門實例Job")//任務備注
                .withIdentity("demoJob","demoGroup")//標識與分組
                .usingJobData("name","張三")//傳入參數
                .usingJobData("sign","abcdefg")
                .build();
        //4.創建任務觸發器
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("demoJob","demoGroup")
                /*.withSchedule(SimpleScheduleBuilder.simpleSchedule()//簡單任務觸發器
                    .withIntervalInSeconds(10)//每10秒執行一次
                    .withRepeatCount(5)//執行5次
                )*/
                .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))//定時觸發調度器
                .startAt(new Date(System.currentTimeMillis()+10))//十秒后開始執行任務
                .build();
        //5.將任務和觸發器注入到quartz中
        scheduler.scheduleJob(jobDetail,trigger);

        //6.啟動任務
        scheduler.start();
    }

}

3.運行測試,注意運行就會觸發一次任務,然后每5秒觸發一次

四、CronExpression表達式詳解

通過使用不難發現任務執行的條件才是我們最關心的,quartz支持Cron表達式來定義觸發器規則。

  • “*”字符被用來指定所有的值。如:”“在分鍾的字段域里表示“每分鍾”。
  • “-”字符被用來指定一個范圍。如:“10-12”在小時域意味着“10點、11點、12點”。
  • “,”字符被用來指定另外的值。如:“MON,WED,FRI”在星期域里表示”星期一、星期三、星期五”.
  • “?”字符只在日期域和星期域中使用。它被用來指定“非明確的值”。當你需要通過在這兩個域中的一個來指定一些東西的時候,它是有用的。看下面的例子你就會明白。
  • “L”字符指定在月或者星期中的某天(最后一天)。即“Last ”的縮寫。但是在星期和月中“L”表示不同的意思,如:在月子段中“L”指月份的最后一天-1月31日,2月28日,如果在星期字段中則簡單的表示為“7”或者“SAT”。如果在星期字段中在某個value值得后面,則表示“某月的最后一個星期value”,如“6L”表示某月的最后一個星期五。
  • “W”字符只能用在月份字段中,該字段指定了離指定日期最近的那個星期日。
  • “#”字符只能用在星期字段,該字段指定了第幾個星期value在某月中

結合示例更加清晰:


免責聲明!

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



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