java框架之Quartz-任務調度&整合Spring

準備

介紹

定時任務,不管是互聯網公司仍是傳統的軟件行業都是必不可少的。Quartz,它是好多優秀的定時任務開源框架的基礎,使用它,咱們可使用最簡單基礎的配置來輕鬆的使用定時任務。java

Quartz 是 OpenSymphony 開源組織在 Job scheduling 領域的又一個開源項目,它能夠與 J2EE 與 J2SE 應用程序相結合也能夠單獨使用。web

Quartz 是開源且具備豐富特性的「任務調度庫」,可以集成與任何的 java 應用,小到獨立的應用,大至電子商業系統。Quartz 可以建立亦簡單亦複雜的調度,以執行上10、上百,甚至上萬的任務。任務 job 被定義爲標準的 java 組件,可以執行任何你想要實現的功能。Quartz 調度框架包含許多企業級的特性,如 JTA 事務、集羣的支持。spring

簡而言之,Quartz 就是基於 java 實現的任務調度框架,用於執行你想要執行的任何任務。apache

Quart 官網 : http://www.quartz-scheduler.org編程

運行環境

  • Quartz 能夠運行嵌入在另外一個獨立式應用程序。
  • Quartz 能夠在應用程序服務器(或 Servlet 容器)內被實例化,而且參與事務。
  • Quartz 能夠做爲一個獨立的程序運行(其本身的 Java 虛擬機內),能夠經過 RMI 調用。
  • Quartz 能夠被實例化,做爲獨立的項目集羣(負載平衡和故障轉移功能),用於做業的執行。

設計模式

  • Builder 模式
  • Factory 模式
  • 組件模式
  • 鏈式編程

核心元素

  • Job(任務)

    Job 就是你想要實現的任務類,每個 Job 必須實現 org.quartz.job 接口,且只需實現接口 定義的 execute 方法。設計模式

  • Trigger(觸發器)

    Trigger 是爲你執行任務的觸發器,好比你想天天定時 3 點發送一封統計郵件,Trigger 將會設置 3 點執行該任務。tomcat

    Trigger 主要包含兩種 SimpleTrigger 和 CronTrigger 兩種。服務器

  • Scheduler(調度器)

    Scheduler 是任務的調度器,它會將任務 Job 及觸發器 Trigger 整合起來,負責基於 Trigger 設定的時間來執行 Job。app

體系結構

經常使用API

如下是 Quartz 編程 API 的幾個重要接口,也是 Quartz 的重要組件。框架

  • Scheduler:用於與調度程序交互的主程序接口。它也是調度程序-任務執行計劃表,只有安排進執行計劃的任務 Job (經過 scheduler,scheduleJob 方法安排進執行計劃),當它預先定義的執行時間到了的時候(任務觸發 Trigger),該任務纔會執行。
  • Job:咱們預先定義的但願在將來時間能被調度程序執行的任務類,咱們能夠自定義。
  • JobDetail:使用 JobDetail 來定義定時任務的實例,JobDetail 實例是經過 JobBuilder 類建立的。
  • JobDataMap:能夠包含不限量(序列化的)數據對象,在 Job 實例執行的時候,可使用其中的數據;JobDataMap 是 Java Map 接口的一個實現,額外增長了一些便於存取基本類型數據的方法。
  • Trigger:觸發器,Trigger 對象是用來觸發執行 Job 的。當調度一個 Job 時,咱們實例一個觸發器而後調整它的屬性來知足 Job 執行的條件。表名任務在何時會執行。定義了一個已經被安排的任務將會在何時執行的時間條件,好比每 2 秒就執行一次。
  • JobBuilder:用於聲明一個任務實例,也能夠定義關於該任務的詳情好比任務名、組名等,這個聲明的實例將會做爲一個實際執行的任務。
  • TriggerBuilder:觸發器建立器,用於建立觸發器 Trigger 實例。
  • JobListener、TriggerListener、SchedulerListener 監聽器,用於對組件的監聽。

使用

入門案例

一、建立 maven java 項目,引入以下依賴:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zze.quertz</groupId>
    <artifactId>quartz_test1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--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>
        <!--整合 log4j-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <!--log4j 依賴-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <target>1.8</target>
                    <source>1.8</source>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
pom.xml

二、建立任務類:

package com.zze.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 {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Date date = new Date();
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
    }
}
com.zze.quartz.job.HelloJob

三、編寫執行類:

package com.zze.quartz.main;

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

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        // 一、調度器(Scheduler),從工廠中獲取調度器實例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // 二、任務實例(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) // 加載任務類,與 HelloJob 完成綁定,需實現 org.quartz.Job 接口
                .withIdentity("job1", "group1") // param1 : 任務的名稱(惟一標示),必須指定 param2 : 任務組名稱,未指定時默認爲 DEFAULT
                .build();
        // 三、觸發器(Trigger)
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") // param1 : 觸發器名稱(惟一標示) param2 : 觸發器組名稱
                .startNow() // 立刻啓動觸發器
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5)) // 每 5 秒重複執行
                .build();
        // 四、讓調度器關聯任務和觸發器,保證按照觸發器定義的條件執行任務
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start(); // 啓動
//        scheduler.shutdown(); // 中止
    }
}

Job和JobDetail介紹

  • Job:工做任務調度的接口,任務類須要實現該接口。該接口中定義 execute 方法,相似 JDK 提供的 TimeTask 類的 run 方法,在裏面編寫任務執行的業務邏輯。
  • Job 實例在 Quartz 中的生命週期:每次調度器執行 Job 時,它在調用 execute 方法前會建立一個新的 Job 實例,當調用完成後,關聯的 Job 對象實例會被釋放,釋放的實例會被垃圾回收機制回收。
  • JobDetail:JobDetail 爲 Job 實例提供了許多設置屬性,以及 JobDataMap 成員變量屬性,它用來存儲特定 Job 實例的狀態信息,調度器須要藉助 JobDetail 對象來添加 Job 實例。
  • JobDetail 的重要屬性:name、group、jobClass、jobDataMap。
    String jobName = jobDetail.getKey().getName();// 任務名稱
    String jobGroupName = jobDetail.getKey().getGroup();// 組名稱
    String jobClassName = jobDetail.getJobClass().getName();// 任務類
    System.out.println(jobName); // job1
    System.out.println(jobGroupName); // group1
    System.out.println(jobClassName); // com.zze.quartz.job.HelloJob

JobExecutingContext介紹

  • 當 Scheduler 調用一個 Job,就會將 JobExecutionContext 傳遞給 Job 的 execute() 方法。
  • Job 能經過 JobExecutionContext 對象訪問到 Quartz 運行時的環境以及 Job 自己的明細數據。
    // 獲取 JobDetail 內容
    JobDetail jobDetail = jobExecutionContext.getJobDetail();
    // 獲取 Trigger 內容
    Trigger trigger = jobExecutionContext.getTrigger();
    // 獲取 Scheduler 內容
    Scheduler scheduler = jobExecutionContext.getScheduler();
    // 獲取當前 job 實例
    Job jobInstance = jobExecutionContext.getJobInstance();
    System.out.println(this == jobInstance); // true
    // 獲取下次執行時間
    Date nextFireTime = jobExecutionContext.getNextFireTime();
    // 獲取上次執行時間
    Date previousFireTime = jobExecutionContext.getPreviousFireTime();
    // 獲取當前執行時間
    Date fireTime = jobExecutionContext.getFireTime();
    // 獲取單次任務執行的惟一標示
    String fireInstanceId = jobExecutionContext.getFireInstanceId();
    // 獲取 JobDataMap
    JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();

JobDataMap

介紹

  • 在進行任務調度時,JobDataMap 存儲在 JobExecutionContext 中,很是方便獲取。
  • JobDataMap 能夠用來裝載任何可序列化的數據對象,當 Job 實例對象被執行時這些參數對象會傳遞給它。
  • JobDataMap 實現了 JDK 的 Map 接口,而且添加了很是方便的方法用來存取基礎數據類型。

數據傳遞

可經過 JobDetail 和 Trigger 傳遞數據給 Job 類,以下:

package com.zze.quartz.main;

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

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .usingJobData("msg","hello job from jobDetail") // 傳遞參數到任務類
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .usingJobData("msg","hello job from trigger") // 傳遞參數到任務類
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}
com.zze.quartz.main.HelloSchedulerDemo :傳遞方

Job 類接收數據有以下兩種方式:

package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

/**
 * 輸出當前時間任務類
 */
public class HelloJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);

        // 經過 JobDetail 獲取 JobDataMap
        JobDataMap jobDetailJobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        String msgFromJobDetail = jobDetailJobDataMap.getString("msg");
        System.out.println(msgFromJobDetail); // hello job from jobDetail
        // 經過 Trigger 獲取 JobDataMap
        JobDataMap triggerJobDataMap = jobExecutionContext.getTrigger().getJobDataMap();
        String msgFromTrigger = triggerJobDataMap.getString("msg");
        System.out.println(msgFromTrigger); // hello job from trigger
    }
}
com.zze.quartz.job.HelloJob :方式一,經過 JobExecutionContext 接收傳遞過來的數據
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

/**
 * 輸出當前時間任務類
 */
public class HelloJob implements Job {

    private String msg;

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);

        System.out.println(msg); // hello job from trigger
    }
}
com.zze.quartz.job.HelloJob :方式二,經過在 Job 類中提供 setter 來接收傳遞過來的數據

注意:經過方式二接收數據時,JobDetail 和 Trigger 傳遞的 key 值不可相同,不然 Trigger 傳遞的數據會覆蓋 JobDetail 傳遞的數據。

有狀態和無狀態的Job

有狀態的 Job 能夠理解爲屢次 Job 調用期間能夠持有一些狀態信息,這些狀態信息存儲在 JobDataMap 中,而默認的無狀態 Job 每次調用都會建立一個新 JobDataMap。

無狀態Job

package com.zze.quartz.main;

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

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .usingJobData("count",0) // 傳遞參數到任務類
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .usingJobData("msg","hello job from trigger") // 傳遞參數到任務類
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}
com.zze.quartz.main.HelloSchedulerDemo
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

public class HelloJob implements Job {

    private Integer count;

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

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
        System.out.println(count);
        count++;
        jobExecutionContext.getJobDetail().getJobDataMap().put("count", count);
    }
}

com.zze.quartz.job.HelloJob

有狀態Job

package com.zze.quartz.main;

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

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .usingJobData("count",0) // 傳遞參數到任務類
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .usingJobData("msg","hello job from trigger") // 傳遞參數到任務類
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}
com.zze.quartz.main.HelloSchedulerDemo
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;

import java.text.SimpleDateFormat;
@PersistJobDataAfterExecution   // 給 Job 添加上該註解那麼該 Job 就變成了有狀態的Job,屢次調用 Job 會保存該 Job 的狀態
public class HelloJob implements Job {

    private Integer count;

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

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
        System.out.println(count);
        count++;
        jobExecutionContext.getJobDetail().getJobDataMap().put("count", count);
    }
}

com.zze.quartz.job.HelloJob

HelloJob 類沒有添加 @PersistJobDataAfterExecution 註解時,每次調用都會新建立一個 JobDataMap,count 不會累加。

HelloJob 類添加 @PersistJobDataAfterExecution 註解時,屢次 Job 調用期間會持久化 JobDataMap 信息,因此能夠實現 count 的累加。

Trigger

介紹

Quartz 有一些不一樣的觸發器類型,不過,用得最多的是 SimpleTrigger 和 CronTrigger。

  • jobKey:標識 Job 實例的標識,觸發器被觸發時,該 Job 實例會被執行。
  • startTime:標識觸發器的時間表,第一次開始被出發的時間。
  • endTime:指定觸發器終止被觸發的時間。

示例

指定任務開始與結束的時間。

package com.zze.quartz.main;

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

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

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException, ParseException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .usingJobData("count",0) // 傳遞參數到任務類
                .build();
        Date startTime = new Date();
        Date endTime = new Date();
        startTime.setTime(startTime.getTime()+3000); // 推遲 3 秒執行
        endTime.setTime(startTime.getTime()+10000); // 推遲 10 秒結束執行
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                // .startNow()
                .startAt(startTime) // 設置開始的時間
                .endAt(endTime) // 設置結束的時間
                .usingJobData("msg","hello job from trigger") // 傳遞參數到任務類
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}
com.zze.quartz.main.HelloSchedulerDemo
package com.zze.quartz.job;

import org.quartz.*;

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

@PersistJobDataAfterExecution   // 給 Job 添加上該註解那麼該 Job 就變成了有狀態的Job,屢次調用 Job 會保存該 Job 的狀態
public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = simpleDateFormat.format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);

        Trigger trigger = jobExecutionContext.getTrigger();
        JobKey jobKey = trigger.getJobKey();
        Date startTime = trigger.getStartTime();
        Date endTime = trigger.getEndTime();
        System.out.printf("開始時間:%s\n", simpleDateFormat.format(startTime));
        System.out.printf("結束時間:%s\n", simpleDateFormat.format(endTime));
    }
}

com.zze.quartz.job.HelloJob

SimpleTrigger觸發器

介紹

在 Quartz 中 SImpleTrigger 對於設置和使用是最爲簡單的一種 Trigger。

它是爲那種須要在特定的日期/時間啓動,且能以一個可能的間隔時間重複執行 n 次的 Job 所設計的。

示例

讓一個任務在指定時間開始執行,而且只重複執行三次。

package com.zze.quartz.main;

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

import java.text.ParseException;
import java.util.Date;

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException, ParseException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .build();
        Date startTime = new Date();
        startTime.setTime(startTime.getTime() + 3000); // 推遲 3 秒執行
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startAt(startTime) // 設置開始的時間
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5).withRepeatCount(3 - 1))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}
com.zze.quartz.main.HelloSchedulerDemo
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = simpleDateFormat.format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
    }
}

com.zze.quartz.job.HelloJob
  • SimpleTrigger 的屬性有:開始時間、結束時間、重複次數和重複的時間間隔。
  • 重複次數屬性的值能夠爲 0 、正整數、或常量 SimpleTrigger.REPEAT_IDENFINITELY (-1)。
  • 重複的時間間隔屬性值必須爲長整型的正整數,以毫秒爲時間單位。
  • 若是有指定結束時間屬性值,則結束時間屬性優先於重複次數屬性。

CronTrigger觸發器

介紹

若是你須要像日曆那樣按日程來出發任務,而不是像 SimpleTrigger 那樣每隔特定的間隔時間觸發,CronTrigger 一般比 SimpleTrigger 更有用,由於它是基於日曆的做業調度器。

使用 CronTrigger,你能夠指定例如「每週五中午 12:00」,或者「每隔工做日的 9:30」或「從每一個周1、周3、週五的上午 9:00 到 上午 10:00 之間每間隔 5 分鐘」這樣的日程安排來觸發。甚至,像 SimpleTrigger 同樣,CronTrigger 也有一個 startTime 以指定日程從何時開始,也有一個 endTime(可選)來指定日程什麼時候終止再也不繼續。

Cron表達式

Cron 表達式用來配置 CronTrigger 實例。Cron 表達式是一個由 7 個子表達式組成的字符串。每一個子表達式都描述了一個單獨的日程細節。這些子表達式用空格分隔,分別表示:

Seconds Minutes Hours DayofMonth Month DayofWeek Year(可選)
各字段含義
字段 容許值 容許的特殊字符
秒(Seconds) 0~59的整數 , - * /    四個字符
分(Minutes) 0~59的整數 , - * /    四個字符
小時(Hours 0~23的整數 , - * /    四個字符
日期(DayofMonth 1~31的整數(可是你須要考慮你月的天數) ,- * ? / L W C     八個字符
月份(Month 1~12的整數或者 JAN-DEC , - * /    四個字符
星期(DayofWeek 1~7的整數或者 SUN-SAT (1=SUN) , - * ? / L C #     八個字符
年(可選,留空)(Year 1970~2099 , - * /    四個字符

每個域均可以使用數字,但還能夠出現以下特殊字符,它們的含義以下:

*:表示匹配該域的任意值。假如在 Minutes 域使用 * , 即表示每分鐘都會觸發事件。
?:只能用在 DayofMonth 和 DayofWeek 兩個域。它也匹配域的任意值,但實際不會。由於 DayofMonth 和 DayofWeek 會相互影響。例如想在每個月的 20 日觸發調度,無論 20 日究竟是星期幾,則只能使用以下寫法: 13 13 15 20 * ?, 其中最後一位只能用 ? ,而不能使用 * ,若是使用 * 表示無論星期幾都會觸發,實際上並非這樣。
-:表示範圍。例如在 Minutes 域使用5-20,表示從5分到20分鐘每分鐘觸發一次 
/:表示起始時間開始觸發,而後每隔固定時間觸發一次。例如在 Minutes 域使用 5/20,則意味着 5 分鐘觸發一次,而 25,45 等分別觸發一次. 
,:表示列出枚舉值。例如:在 Minutes 域使用 5,20,則意味着在 5 和 20 分分別觸發一次。 
L:表示最後,只能出如今 DayofWeek 和 DayofMonth 域。若是在 DayofWeek 域使用 5L,意味着在最後的一個星期四觸發。 
W:表示有效工做日(週一到週五),只能出如今 DayofMonth 域,系統將在離指定日期的最近的有效工做日觸發事件。例如:在 DayofMonth 使用 5W,若是 5 日是星期六,則將在最近的工做日:星期五,即 4 日觸發。若是 5 日是星期天,則在 6 日(週一)觸發;若是 5 日在星期一到星期五中的一天,則就在 5 日觸發。另一點,W 的最近尋找不會跨過月份 。
LW:這兩個字符能夠連用,表示在某個月最後一個工做日,即最後一個星期五。 
#:用於肯定每月第幾個星期幾,只能出如今 DayofMonth 域。例如 4#2,表示某月的第二個星期三。

經常使用表達式示例:

0 0 2 1 * ? *   表示在每個月的 1 日的凌晨 2 點
0 15 10 ? * MON-FRI   表示週一到週五天天上午 10:15 
0 15 10 ? 6L 2002-2006   表示 2002-2006 年的每月的最後一個星期五上午 10:15 
0 0 10,14,16 * * ?   天天上午 10 點,下午 2 點,4 點 
0 0/30 9-17 * * ?   朝九晚五工做時間內每半小時 
0 0 12 ? * WED    表示每一個星期三中午 12 點 
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:10 和 2: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 觸發

在線Cron表達式生成器

示例

package com.zze.quartz.main;

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

import java.text.ParseException;

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException, ParseException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .build();

        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                // 使用 Cron 調度器
                .withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * 6 3 ?")) // 3 月 6 號 每隔 3 秒觸發
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
    }
}
com.zze.quartz.main.HelloSchedulerDemo
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = simpleDateFormat.format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
    }
}

com.zze.quartz.job.HelloJob

Scheduler

相關API

scheduler.start(); // 調度器啓動
scheduler.standby(); // 掛起
scheduler.shutdown(false); // 當即關閉調度器
scheduler.shutdown(true); // 等待全部任務執行完畢後再終止調度器

配置

經過以前的學習已經知道,調度器實例是經過 StdSchedulerFactory.getDefaultScheduler() 建立。查看該部分源碼會發現,建立調度器時加載了以下屬性文件:

# 用來區分特定的調度器實例,能夠按照功能用途給調度器起名
org.quartz.scheduler.instanceName:DefaultQuartzScheduler
# 這個屬性與前者同樣,容許任意字符串,但這個值必須在全部調度器實例中是惟一的,尤爲是再一個集羣環境中,做爲集羣的惟一 key。設爲 auto 即讓 Quartz 自動生成這個值
org.quartz.scheduler.instanceId:auto

org.quartz.scheduler.rmi.export:false

org.quartz.scheduler.rmi.proxy:false

org.quartz.scheduler.wrapJobExecutionInUserTransaction:false
#Quartz 自帶的線程池實現類,實現了 org.quartz.threadPool
org.quartz.threadPool.class:org.quartz.simpl.SimpleThreadPool

# 處理 Job 的線程個數,至少爲 1 ,最多最好不要超過 100。
org.quartz.threadPool.threadCount:10
# 線程的優先級,優先級別高的線程比級別低的線程優先獲得執行。最小爲 1 ,最大爲 10,默認 爲 5
org.quartz.threadPool.threadPriority:5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:true

org.quartz.jobStore.misfireThreshold:60000

org.quartz.jobStore.class:org.quartz.simpl.RAMJobStore
quartz-2.3.0.jar!/org/quartz/quartz.properties

咱們能夠在 classpath 下提供一個和上述同名的一個屬性文件來覆蓋 Quartz 的默認配置,也能夠經過以下方式手動加載配置文件來初始化調度器:

StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
// stdSchedulerFactory.initialize(String fileName);
// stdSchedulerFactory.initialize(Properties properties);
// stdSchedulerFactory.initialize(InputStream propertiesStream);
Scheduler scheduler = stdSchedulerFactory.getScheduler();

Listener

介紹

Quartz 的監聽器用於在任務調度中你咱們所關注的事件發生時,可以及時獲取這一事件的通知。相似於任務執行過程當中的郵件、短信的提醒。Quartz 監聽器主要有 JobListener、TriggerListener、SchedulerListener 三種,顧名思義,分別表示任務、觸發器、調度器對應的監聽器,三者的使用方法相似。

而這幾種監聽器又分爲兩類,全局監聽器和非全局監聽器,兩者的區別在於:全局監聽器可以接收到全部的 Job/Trigger 的時間通知;而非全局監聽器只能接收到在其上註冊的 Job 或 Trigger 事件,不在其上註冊的 Job 或 Trigger 則不會監聽。

JobListener

任務調度過程當中,與任務 Job 相關的事件包括:Job 要開始執行時、Job 執行完成時。要定義一個任務監聽器,須要實現 JobListener 接口:

package org.quartz;

public interface JobListener {
    // 獲取 JobListener 的名稱
    String getName();
    // Scheduler 在 JobDetail 將要被執行時調用
    void jobToBeExecuted(JobExecutionContext var1);
    // Scheduler 在 JobDetail 即將被執行,但又被 TriggerListener 否決時調用
    void jobExecutionVetoed(JobExecutionContext var1);
    // Scheduler 在 JobDetail 被執行以後調用這個方法
    void jobWasExecuted(JobExecutionContext var1, JobExecutionException var2);
}
org.quartz.JobListener

使用示例:

package com.zze.quartz.listener;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;

public class HelloJobListener implements JobListener {
    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
        String jobName = jobExecutionContext.getJobDetail().getKey().getName();
        System.out.printf("jobToBeExecuted---Job的名稱爲:%s,Scheduler 在 Job 將要被執行時調用該方法\n", jobName);
    }

    @Override
    public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {
        String jobName = jobExecutionContext.getJobDetail().getKey().getName();
        System.out.printf("jobExecutionVetoed---Job的名稱爲:%s,Scheduler 在 Job 即將被執行,但又被 TriggerListener 否決時調用該方法\n", jobName);
    }

    @Override
    public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
        String jobName = jobExecutionContext.getJobDetail().getKey().getName();
        System.out.printf("jobExecutionVetoed---Job的名稱爲:%s,Scheduler 在 Job 執行完成以後調用該方法\n\n", jobName);
    }
}
com.zze.quartz.listener.HelloJobListener:任務監聽器
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = simpleDateFormat.format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
    }
}
com.zze.quartz.job.HelloJob:任務類
package com.zze.quartz.main;

import com.zze.quartz.job.HelloJob;
import com.zze.quartz.listener.HelloJobListener;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.KeyMatcher;

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(3))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        // 註冊全局 Job 監聽器
//        scheduler.getListenerManager().addJobListener(new HelloJobListener(), EverythingMatcher.allJobs());
        // 註冊局部 Job 監聽器,對指定組、指定名稱的 Job 進行監聽
        scheduler.getListenerManager().addJobListener(new HelloJobListener(), KeyMatcher.keyEquals(JobKey.jobKey("job1", "group1")));
        scheduler.start();
    }
}

com.zze.quartz.main.HelloSchedulerDemo:註冊監聽器

TriggerListener

任務調度過程當中,與觸發器 Trigger 相關的事件包括:觸發器觸發時、觸發器未正常觸發時、觸發器完成時等。要定義一個觸發器監聽器,須要實現 TriggerListener 接口:

package org.quartz;

import org.quartz.Trigger.CompletedExecutionInstruction;

public interface TriggerListener {
    // 獲取 Trigger 名稱
    String getName();
    // 當與監聽器相關聯的 Trigger 被觸發,Job 上的 execute() 方法將被執行時,Scheduler 就調用該方法。
    void triggerFired(Trigger var1, JobExecutionContext var2);
    // 在 Trigger 觸發後,Job 將要被執行時由 Scheduler 調用該方法。TriggerListener 給了一個選擇去否決 Job 的執行。假如這個方法返回 true,這個 Job 將不會爲這次 Trigger 觸發而獲得執行。
    boolean vetoJobExecution(Trigger var1, JobExecutionContext var2);
    // Scheduler 調用這個方法是在 Trigger 錯過觸發時。
    void triggerMisfired(Trigger var1);
    // Trigger 被觸發而且完成了 Job 的執行時,Scheduler 調用這個方法。
    void triggerComplete(Trigger var1, JobExecutionContext var2, CompletedExecutionInstruction var3);
}
org.quartz.TriggerListener

使用示例:

package com.zze.quartz.listener;

import org.quartz.JobExecutionContext;
import org.quartz.Trigger;
import org.quartz.TriggerListener;

public class HelloTriggerListener implements TriggerListener {
    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
        String triggerName = trigger.getKey().getName();
        System.out.printf("triggerFired---%s 將要被觸發\n", triggerName);
    }

    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
        String triggerName = trigger.getKey().getName();
        boolean isTrigger = false;
        String msg = !isTrigger ? "容許被觸發" : "拒絕被觸發";
        System.out.printf("vetoJobExecution---%s %s\n", triggerName, msg);
        return isTrigger; // 若是返回 true,將不會執行 Job 的方法。
    }

    @Override
    public void triggerMisfired(Trigger trigger) {
        String triggerName = trigger.getKey().getName();
        System.out.printf("triggerMisfired---%s 錯過觸發\n", triggerName);
    }

    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
        String triggerName = trigger.getKey().getName();
        System.out.printf("triggerComplete---%s 觸發完成\n\n", triggerName);
    }
}
com.zze.quartz.listener.HelloTriggerListener:觸發器監聽器
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = simpleDateFormat.format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
    }
}
com.zze.quartz.job.HelloJob:任務類
package com.zze.quartz.main;

import com.zze.quartz.job.HelloJob;
import com.zze.quartz.listener.HelloTriggerListener;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.EverythingMatcher;
import org.quartz.impl.matchers.KeyMatcher;

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(3))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        // 註冊一個全局的 Trigger 監聽器
        // scheduler.getListenerManager().addTriggerListener(new HelloTriggerListener(), EverythingMatcher.allTriggers());
        // 註冊一個局部的 Trigger 監聽器
        scheduler.getListenerManager().addTriggerListener(new HelloTriggerListener(), KeyMatcher.keyEquals(TriggerKey.triggerKey("trigger1", "group1")));
        scheduler.start();
    }
}

com.zze.quartz.main.HelloSchedulerDemo:註冊監聽器

SchedulerListener

任務調度過程當中,與調度器有關的事件包括:增長一個 Job/Trigger、刪除一個 Job/Trigger、Scheduler 發生錯誤、關閉 Scheduler 等。要定義一個調度器監聽器,須要實現 SchedulerListener 接口:

package org.quartz;

public interface SchedulerListener {
    // 部署 JobDetail 時調用
    void jobScheduled(Trigger trigger);
    // 卸載 JobDetail 時調用
    void jobUnscheduled(TriggerKey triggerKey);
    // 當一個 Trigger 不再會觸發時調用,若這個觸發器對應的 Job 沒有狀態持久化,則將會從 Scheduler 中移除
    void triggerFinalized(Trigger trigger);
    // 在一個 Trigger 被暫停時
    void triggerPaused(TriggerKey triggerKey);
    // 在一個 TriggerGroup 被暫停時
    void triggersPaused(String triggerGroup);
    // 在一個 Trigger 恢復時
    void triggerResumed(TriggerKey triggerKey);
    // 在一個 TriggerGroup 恢復時
    void triggersResumed(String var1);
    // 當新加入一個 Job 時
    void jobAdded(JobDetail jobDetail);
    // 當移除一個 Job 時
    void jobDeleted(JobKey jobKey);
    // 當 Job 暫停時
    void jobPaused(JobKey jobKey);
    // 當 JobGroup 暫停時
    void jobsPaused(String jobGroup);
    // 當 Job 恢復時
    void jobResumed(JobKey jobKey);
    // 當 JobGroup 恢復時
    void jobsResumed(String jobGroup);
    // 當 Scheduler 運行期出現錯誤時
    void schedulerError(String msg, SchedulerException cause);
    // 當 Scheduler 掛起時
    void schedulerInStandbyMode();
    // 當 Scheduler 開始後
    void schedulerStarted();
    // 當 Scheduler 開始時
    void schedulerStarting();
    // 當 Scheduler 關閉後
    void schedulerShutdown();
    // 當 Scheduler 關閉時
    void schedulerShuttingdown();
    // 當 Scheduler 中數據被清除時
    void schedulingDataCleared();
}
org.quartz.SchedulerListener

使用示例:

package com.zze.quartz.listener;

import org.quartz.*;

public class HelloSchedulerListener implements SchedulerListener {

    @Override
    public void jobScheduled(Trigger trigger) {
        String name = trigger.getKey().getName();
        System.out.println(name + "完成部署");
    }

    @Override
    public void jobUnscheduled(TriggerKey triggerKey) {
        String name = triggerKey.getName();
        System.out.println(name + "完成卸載");
    }

    @Override
    public void triggerFinalized(Trigger trigger) {
        System.out.println(trigger.getKey().getName() + "觸發器已移除");
    }

    @Override
    public void triggerPaused(TriggerKey triggerKey) {
        System.out.println(triggerKey.getName() + "觸發器被暫停");
    }

    @Override
    public void triggersPaused(String triggerGroup) {
        System.out.println(triggerGroup + "觸發器組被暫停");
    }

    @Override
    public void triggerResumed(TriggerKey triggerKey) {
        System.out.println(triggerKey.getName() + "觸發器恢復");
    }

    @Override
    public void triggersResumed(String triggerGroup) {
        System.out.println(triggerGroup + "觸發器組恢復");
    }

    @Override
    public void jobAdded(JobDetail jobDetail) {
        System.out.println(jobDetail.getKey().getName() + "任務已添加");
    }

    @Override
    public void jobDeleted(JobKey jobKey) {
        System.out.println(jobKey.getName() + "任務已刪除");
    }

    @Override
    public void jobPaused(JobKey jobKey) {
        System.out.println(jobKey.getName() + "任務已暫停");
    }

    @Override
    public void jobsPaused(String jobGroup) {
        System.out.println(jobGroup + "任務組已暫停");
    }

    @Override
    public void jobResumed(JobKey jobKey) {
        System.out.println(jobKey.getName() + "任務已恢復");
    }

    @Override
    public void jobsResumed(String jobGroup) {
        System.out.println(jobGroup + "任務組已恢復");
    }

    @Override
    public void schedulerError(String msg, SchedulerException cause) {
        System.out.println("調度器發生錯誤:"+msg);
    }

    @Override
    public void schedulerInStandbyMode() {
        System.out.println("調度器掛起");
    }

    @Override
    public void schedulerStarted() {
        System.out.println("調度器已開始");
    }

    @Override
    public void schedulerStarting() {
        System.out.println("調度器正在開始");
    }

    @Override
    public void schedulerShutdown() {
        System.out.println("調度器關閉");
    }

    @Override
    public void schedulerShuttingdown() {
        System.out.println("調度器關閉中");
    }

    @Override
    public void schedulingDataCleared() {
        System.out.println("調度器數據被清理");
    }
}
com.zze.quartz.listener.HelloSchedulerListener:調度器監聽器
package com.zze.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = simpleDateFormat.format(jobExecutionContext.getFireTime());
        System.out.println("正在執行 xxx 任務,時間爲" + dateStr);
    }
}
com.zze.quartz.job.HelloJob:任務類
package com.zze.quartz.main;

import com.zze.quartz.job.HelloJob;
import com.zze.quartz.listener.HelloSchedulerListener;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class HelloSchedulerDemo {
    public static void main(String[] args) throws SchedulerException {
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(3))
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
        // 註冊調度器監聽
        scheduler.getListenerManager().addSchedulerListener(new HelloSchedulerListener());
        scheduler.start();
    }
}

com.zze.quartz.main.HelloSchedulerDemo:註冊監聽器

Spring集成Quartz

依賴

建立 maven web 工程,引入如下依賴:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zze.quartz</groupId>
    <artifactId>quartz_spring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.3</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
pom.xml

加載 Spring 核心配置文件:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>
WEB-INF/web.xml

XML方式

一、建立任務類:

package com.zze.quartz;

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

public class HelloJob {
    public void run() {
        System.out.println("Hello quartz! now ->" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}
com.zze.quartz.HelloJob

 二、Spring 配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 定時任務的bean -->
    <bean id="helloJob" class="com.zze.quartz.HelloJob"/>

    <bean id="testQuartzJob_jd"
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject">
            <ref bean="helloJob"/>
        </property>
        <property name="targetMethod" value="run"></property>
    </bean>

    <!-- 調度的配置&job的配置 -->
    <bean id="testQuartzJob_ct" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail">
            <ref bean="testQuartzJob_jd"/>
        </property>
        <!--每五秒執行-->
        <property name="cronExpression" value="*/5 * * * * ?"></property>
    </bean>

    <!-- 開啓定時任務-->
    <bean id="startQuertz" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="testQuartzJob_ct"/>
            </list>
        </property>
    </bean>
</beans>
applicationContext.xml

三、啓動項目,觀察控制檯:

註解方式

一、建立任務類並使用註解:

package com.zze.quartz;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class HelloJob {
    @Scheduled(cron = "*/1 * * * * ?") // 每秒執行
    public void run() {
        System.out.println("Hello quartz! now ->" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}
com.zze.quartz.HelloJob

二、配置 Spring 包掃描:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/task
    http://www.springframework.org/schema/task/spring-task-3.0.xsd">

    <!-- task任務掃描註解 -->
    <task:annotation-driven/>
    <!-- 掃描位置 -->
    <context:component-scan base-package="com.zze.quartz"/>
</beans>
applicationContext.xml

三、啓動項目,觀察控制檯:

相關文章
相關標籤/搜索