定時任務框架Quartz-(一)Quartz入門與Demo搭建

注:本文來源於:是Guava不是瓜娃  《定時任務框架Quartz-(一)Quartz入門與Demo搭建java

1、什麼是Quartz

什麼是Quartz?

Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,徹底由Java開發,能夠用來執行定時任務,相似於java.util.Timer。可是相較於Timer, Quartz增長了不少功能:

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

大部分公司都會用到定時任務這個功能。
拿火車票購票來講,當你下單後,後臺就會插入一條待支付的task(job),通常是30分鐘,超過30min後就會執行這個job,去判斷你是否支付,未支付就會取消這次訂單;當你支付完成以後,後臺拿到支付回調後就會再插入一條待消費的task(job),Job觸發日期爲火車票上的出發日期,超過這個時間就會執行這個job,判斷是否使用等。併發

如何實現

在咱們實際的項目中,當Job過多的時候,確定不能人工去操做,這時候就須要一個任務調度框架,幫咱們自動去執行這些程序。那麼該如何實現這個功能呢?框架

(1)首先咱們須要定義實現一個定時功能的接口,咱們能夠稱之爲Task(或Job),如定時發送郵件的task(Job),重啓機器的task(Job),優惠券到期發送短信提醒的task(Job),實現接口以下:
dom


(2)有了任務以後,還須要一個可以實現觸發任務去執行的觸發器,觸發器Trigger最基本的功能是指定Job的執行時間,執行間隔,運行次數等。ide

(3)有了Job和Trigger後,怎麼樣將二者結合起來呢?即怎樣指定Trigger去執行指定的Job呢?這時須要一個Schedule,來負責這個功能的實現。工具



上面三個部分就是Quartz的基本組成部分:測試

  • 調度器:Scheduler
  • 任務:JobDetail
  • 觸發器:Trigger,包括SimpleTrigger和CronTrigger

2、Quartz Demo搭建

下面來利用Quartz搭建一個最基本的Demo。
ui

一、導入依賴的jar包:

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

二、新建一個可以打印任意內容的Job:

 package com.todaytech.GdsdFs.QuartzDemo.Demo2;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
 * 新建一個可以打印任意內容的Job:
 * @author admin
 *
 */
public class PrintWordsJob implements Job{

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
        System.out.println("PrintWordsJob start at:" + printTime + ", prints: Hello Job-" + new Random().nextInt(100));

    }
}


三、建立Schedule,執行任務:

 package com.todaytech.GdsdFs.QuartzDemo.Demo2;

import java.util.concurrent.TimeUnit;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 建立Schedule,執行任務:
 * @author admin
 *
 */
public class MyScheduler {
	public static void main(String[] args) throws SchedulerException, InterruptedException {
        // 一、建立調度器Scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        // 二、建立JobDetail實例,並與PrintWordsJob類綁定(Job執行內容)
        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class).withIdentity("job1", "group1").build();
        // 三、構建Trigger實例,每隔1s執行一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .startNow()//當即生效
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1)//每隔1s執行一次
                .repeatForever()).build();//一直執行

        //四、執行
        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("--------scheduler start ! ------------");
        scheduler.start();

        //睡眠
        TimeUnit.MINUTES.sleep(1);
        scheduler.shutdown();
        System.out.println("--------scheduler shutdown ! ------------");


    }
}

運行程序,能夠看到程序每隔1s會打印出內容,且在一分鐘後結束:spa


3、Quartz核心詳解


下面就程序中出現的幾個參數,看一下Quartz框架中的幾個重要參數:.net

Job和JobDetail
JobExecutionContext
JobDataMap
Trigger、SimpleTrigger、CronTrigger

(1)Job和JobDetail


Job是Quartz中的一個接口,接口下只有execute方法,在這個方法中編寫業務邏輯。
接口中的源碼:


JobDetail用來綁定Job,爲Job實例提供許多屬性:

name
group
jobClass
jobDataMap
JobDetail綁定指定的Job,每次Scheduler調度執行一個Job的時候,首先會拿到對應的Job,而後建立該Job實例,再去執行Job中的execute()的內容,任務執行結束後,關聯的Job對象實例會被釋放,且會被JVM GC清除。

爲何設計成JobDetail + Job,不直接使用Job

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


(2)JobExecutionContext


JobExecutionContext中包含了Quartz運行時的環境以及Job自己的詳細數據信息。
當Schedule調度執行一個Job的時候,就會將JobExecutionContext傳遞給該Job的execute()中,Job就能夠經過JobExecutionContext對象獲取信息。
主要信息有:


(3)JobExecutionContext


JobDataMap實現了JDK的Map接口,能夠以Key-Value的形式存儲數據。
JobDetail、Trigger均可以使用JobDataMap來設置一些參數或信息,
Job執行execute()方法的時候,JobExecutionContext能夠獲取到JobExecutionContext中的信息:
如:


JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class).usingJobData("jobDetail1", "這個Job用來測試的")
                  .withIdentity("job1", "group1").build();

 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
      .usingJobData("trigger1", "這是jobDetail1的trigger")
      .startNow()//當即生效
      .withSchedule(SimpleScheduleBuilder.simpleSchedule()
      .withIntervalInSeconds(1)//每隔1s執行一次
      .repeatForever()).build();//一直執行


Job執行的時候,能夠獲取到這些參數信息:

@Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("jobDetail1"));
        System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("trigger1"));
        String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
        System.out.println("PrintWordsJob start at:" + printTime + ", prints: Hello Job-" + new Random().nextInt(100));


    }

4)Trigger、SimpleTrigger、CronTrigger

  • Trigger

Trigger是Quartz的觸發器,會去通知Scheduler什麼時候去執行對應Job。

new Trigger().startAt():表示觸發器首次被觸發的時間;
new Trigger().endAt():表示觸發器結束觸發的時間;
  • SimpleTrigger
    SimpleTrigger能夠實如今一個指定時間段內執行一次做業任務或一個時間段內屢次執行做業任務。
    下面的程序就實現了程序運行5s後開始執行Job,執行Job 5s後結束執行:


Date startDate = new Date();
startDate.setTime(startDate.getTime() + 5000);

 Date endDate = new Date();
 endDate.setTime(startDate.getTime() + 5000);

        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData("trigger1", "這是jobDetail1的trigger")
                .startNow()//當即生效
                .startAt(startDate)
                .endAt(endDate)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1)//每隔1s執行一次
                .repeatForever()).build();//一直執行 


CronTrigger
CronTrigger功能很是強大,是基於日曆的做業調度,而SimpleTrigger是精準指定間隔,因此相比SimpleTrigger,CroTrigger更加經常使用。CroTrigger是基於Cron表達式的,先了解下Cron表達式:
由7個子表達式組成字符串的,格式以下:

[秒] [分] [小時] [日] [月] [周] [年]

Cron表達式的語法比較複雜,
如:* 30 10 ? * 1/5 *
表示(從後往前看)
[指定年份] 的[ 週一到週五][指定月][不指定日][上午10時][30分][指定秒]

又如:00 00 00 ? * 10,11,12 1#5 2018
表示2018年十、十一、12月的第一週的星期五這一天的0時0分0秒去執行任務。

下面是給的一個例子:


可經過在線生成Cron表達式的工具:http://cron.qqe2.com/ 來生成本身想要的表達式。

這裏寫圖片描述

下面的代碼就實現了每週一到週五上午10:30執行定時任務

 package com.todaytech.GdsdFs.QuartzDemo.Demo2;

import java.util.Date;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
/**
 * 下面的代碼就實現了每週一到週五上午10:30執行定時任務
 * @author admin
 *
 */
public class MyScheduler2 {
	 public static void main(String[] args) throws SchedulerException, InterruptedException {
	        // 一、建立調度器Scheduler
	        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
	        Scheduler scheduler = schedulerFactory.getScheduler();
	        // 二、建立JobDetail實例,並與PrintWordsJob類綁定(Job執行內容)
	        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)
	                .usingJobData("jobDetail1", "這個Job用來測試的")
	                .withIdentity("job1", "group1").build();
	        // 三、構建Trigger實例,每隔1s執行一次
	        Date startDate = new Date();
	        startDate.setTime(startDate.getTime() + 5000);

	        Date endDate = new Date();
	        endDate.setTime(startDate.getTime() + 5000);

	        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
	                .usingJobData("trigger1", "這是jobDetail1的trigger")
	                .startNow()//當即生效
	                .startAt(startDate)
	                .endAt(endDate)
	                .withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018"))
	                .build();

	        //四、執行
	        scheduler.scheduleJob(jobDetail, cronTrigger);
	        System.out.println("--------scheduler start ! ------------");
	        scheduler.start();
	        System.out.println("--------scheduler shutdown ! ------------");

	    }
}
相關文章
相關標籤/搜索