java基礎(chǔ)-day61-Quartz

Quartz


1.1 簡介

Quartzhttp://www.quartz-scheduler.org/

是一個(gè)定時(shí)任務(wù)調(diào)度框架。比如你遇到這樣的問題:

  • 想在30分鐘后,查看訂單是否支付,未支付則取消訂單
  • 想在每月29號,信用卡自動還款
  • ...
  • 想定時(shí)在某個(gè)時(shí)間,去做某件事(任務(wù))。

Quartz是要做定時(shí)任務(wù)的調(diào)度,設(shè)置好觸發(fā)時(shí)間規(guī)則,以及相應(yīng)的任務(wù)(Job)即可。

二、Quartz使用


2.1 導(dǎo)入依賴

<dependencies>
    <!--Quartz任務(wù)調(diào)度-->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.3.2</version>
    </dependency>
</dependencies>

2.2 定義Job

/**
 * 工作類的具體實(shí)現(xiàn),即需要定時(shí)執(zhí)行的“某件事”
 * */
public class MyJob implements Job {
    //執(zhí)行
    public void execute(JobExecutionContext context) throws JobExecutionException {
         //創(chuàng)建工作詳情
        JobDetail jobDetail=context.getJobDetail();
        //獲取工作的名稱
        String jobName = jobDetail.getKey().getName();//任務(wù)名
        String jobGroup = jobDetail.getKey().getGroup();//任務(wù)group
        System.out.println("job執(zhí)行,job:"+jobName+" group:"+jobGroup);
        System.out.println(new Date());
    }
}

2.3 API測試

package com.qf;

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

import java.util.GregorianCalendar;

public class TestQuartz {

    public static void main(String[] args) throws Exception{
        //創(chuàng)建scheduler,調(diào)度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //定義一個(gè)Trigger,觸發(fā)條件類
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1") //定義name/group
                .startNow()//設(shè)置開始時(shí)間,一旦加入scheduler,表示立即生效,即開始計(jì)時(shí)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(2) //每隔2秒執(zhí)行一次
                        //.repeatForever()) //一直執(zhí)行,直到結(jié)束時(shí)間
                        .withRepeatCount(3))//設(shè)置執(zhí)行次數(shù)
                //設(shè)置結(jié)束時(shí)間(注:月份默認(rèn)從0開始)
                .endAt(new GregorianCalendar(2020,5,27,17,30,10).getTime())
                .build();
        //定義一個(gè)JobDetail
        JobDetail job = JobBuilder.newJob(MyJob.class)
                .withIdentity("job1","group1") //定義name/group
                .build();
        //調(diào)度器 中加入 任務(wù)和觸發(fā)器
        scheduler.scheduleJob(job, trigger);
        //啟動任務(wù)調(diào)度
        scheduler.start();
    }
}

2.4 默認(rèn)配置

# 名為:quartz.properties,放置在classpath下,如果沒有此配置則按默認(rèn)配置啟動
# 指定調(diào)度器名稱,非實(shí)現(xiàn)類
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
# 指定線程池實(shí)現(xiàn)類
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 線程池線程數(shù)量
org.quartz.threadPool.threadCount = 10 
# 優(yōu)先級,默認(rèn)5
org.quartz.threadPool.threadPriority = 5
# 非持久化job
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

2.5 核心類說明

Scheduler:調(diào)度器。所有的調(diào)度都是由它控制,是Quartz的大腦,所有任務(wù)都是由它來管理

Job:任務(wù),想定時(shí)執(zhí)行的事情(定義業(yè)務(wù)邏輯)

JobDetail:基于Job,進(jìn)一步包裝。其中關(guān)聯(lián)一個(gè)Job,并為Job指定更詳細(xì)的屬性,比如標(biāo)識等

Trigger:觸發(fā)器。可以指定給某個(gè)任務(wù),指定任務(wù)的觸發(fā)機(jī)制。

三、Trigger


3.1 SimpleTrigger

以一定的時(shí)間間隔(單位是毫秒)執(zhí)行的任務(wù)。

  • 指定起始和截止時(shí)間(時(shí)間段)
  • 指定時(shí)間間隔、執(zhí)行次數(shù)

示例:

SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                          .withIntervalInSeconds(1) //每秒執(zhí)行一次
                          .repeatForever())// 不限執(zhí)行次數(shù)
                .endAt(new GregorianCalendar(2020, 4, 7, 2, 24, 0).getTime())
                .build();
SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                          .withIntervalInMinutes(3) // 每3分鐘執(zhí)行一次
                          .withRepeatCount(3)) // 執(zhí)行次數(shù)不超過3次
                .endAt(new GregorianCalendar(2020, 4, 7, 2, 24, 0).getTime()) 
                .build();

3.2 CronTrigger 【重點(diǎn)

適合于更復(fù)雜的任務(wù),它支持類型于Linux Cron的語法(并且更強(qiáng)大)。

  • 指定Cron表達(dá)式即可

示例:

// 每天10:00-12:00,每隔2秒鐘執(zhí)行一次
CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger2", "group2")
                .withSchedule(CronScheduleBuilder.cronSchedule("*/2 * 10-12 * * ?"))
                .build(); 
3.2.1 Cron表達(dá)式組成

表達(dá)式組成:"秒 分 時(shí) 日 月 星期幾 [年]" ,其中"年" 是可選的,一般不指定。

  • 如:"10 20 18 3 5 ?"代表"5月3日18點(diǎn)20分10秒,星期幾不確定 "
位置 時(shí)間域 允許值 特殊值
1 0-59 , - * /
2 分鐘 0-59 , - * /
3 小時(shí) 0-23 , - * /
4 日期 1-31 , - * ? / L W
5 月份 1-12 , - * /
6 星期 1-7 , - * ? / L #
7 年份(可選) , - * /
3.2.2 Cron表達(dá)式符號

表達(dá)式中可使用的特殊符號的含義如下

符號 語義
星號(*) 可用在所有字段中,表示對應(yīng)時(shí)間域的每一個(gè)時(shí)刻,例如, 在分鐘字段時(shí),表示“每分鐘”
問號(?) 該字符只在日期和星期字段中使用,它通常指定為“不確定值”
減號(-) 表達(dá)一個(gè)范圍,如在小時(shí)字段中使用“10-12”,則表示從10到12點(diǎn),即10,11,12
逗號(,) 表達(dá)一個(gè)列表值,如在星期字段中使用“MON,WED,FRI”,則表示星期一,星期三和星期五
斜杠(/) x/y表達(dá)一個(gè)等步長序列,x為起始值,y為增量步長值。如在分鐘字段中使用0/15,則表示為0,15,30和45秒,而5/15在分鐘字段 中表示5,20,35,50
井號(#) 該字符只用在星期字段中,"4#2"代表第二個(gè)星期3,“5#4”代表第4個(gè)星期四
L 該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個(gè)字段中意思不同。
如果L用在星期字段里,則表示星期六,等同于7
L出現(xiàn)在星期字段里,而且在前面有一個(gè)數(shù)值x,則表示“這個(gè)月的最后一個(gè)周x”,例如,6L表示該月的最后星期五
L在日期字段中,表示這個(gè)月份的最后一天,如一月的31號,非閏年二月的28號
W 該字符只能出現(xiàn)在日期字段里,是對前導(dǎo)日期的修飾,表示離該日期最近的工作日
例如15W表示離該月15號最近的工作日,如果該月15號是星期六,則匹配14號星期五;如果15日是星期日,則匹配16號星期一;如果15號 是星期二,那結(jié)果就是15號星期二;但必須注意關(guān)聯(lián)的匹配日期不能夠跨月
LW組合 在日期字段可以組合使用LW,它的意思是當(dāng)月的最后一個(gè)工作日
3.2.3 Cron表達(dá)式示例

演示實(shí)例

表示式 說明
0 0 12 * * ? 每天12點(diǎn)運(yùn)行
0 15 10 * * ? 每天10:15運(yùn)行
0 15 10 * * ? 2008 在2008年的每天10:15運(yùn)行
0 * 14 * * ? 每天14點(diǎn)到15點(diǎn)之間每分鐘運(yùn)行一次,開始于14:00,結(jié)束于14:59。
0 0/5 14 * * ? 每天14點(diǎn)到15點(diǎn)每5分鐘運(yùn)行一次,開始于14:00,結(jié)束于14:55。
0 0/5 14,18 * * ? 每天14點(diǎn)到15點(diǎn)每5分鐘運(yùn)行一次,此外每天18點(diǎn)到19點(diǎn)每5鐘也運(yùn)行一次。
0 0-5 14 * * ? 每天14:00點(diǎn)到14:05,每分鐘運(yùn)行一次。
0 0-5/2 14 * * ? 每天14:00點(diǎn)到14:05,每2分鐘運(yùn)行一次。
0 10,44 14 ? 3 4 3月每周三的14:10分和14:44分,各運(yùn)行一次。
0 15 10 ? * 2-6 每周一,二,三,四,五的10:15分運(yùn)行一次。
0 15 10 15 * ? 每月15日10:15分運(yùn)行。
0 15 10 L * ? 每月最后一天10:15分運(yùn)行。
0 15 10 ? * 6L 每月最后一個(gè)星期五10:15分運(yùn)行。【此時(shí)天必須是"?"】
0 15 10 ? * 6L 2007-2009 在2007,2008,2009年每個(gè)月的最后一個(gè)星期五的10:15分運(yùn)行。

四、Spring整合Quartz 【重點(diǎn)

4.1 依賴

<dependencies>
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.3.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.2.6.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.2.6.RELEASE</version>
    </dependency>
</dependencies>

4.2 定義Job

定義一個(gè)Job類

public class MyJob implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.err.println("job 執(zhí)行"+new Date());
    }
}

4.3 配置applicationContext.xml

調(diào)度器 SchedulerFactoryBean

觸發(fā)器 CronTriggerFactoryBean

JobDetail JobDetailFactoryBean

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

    <!--
        Spring整合Quartz進(jìn)行配置遵循下面的步驟:
        1:定義工作任務(wù)的Job
        2:定義觸發(fā)器Trigger,并將觸發(fā)器與工作任務(wù)綁定
        3:定義調(diào)度器,并將Trigger注冊到Scheduler
     -->

    <!-- 1:定義任務(wù)的bean ,這里使用JobDetailFactoryBean,也可以使用MethodInvokingJobDetailFactoryBean ,配置類似-->
    <bean name="lxJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <!-- 指定job的名稱 -->
        <property name="name" value="job1"/>
        <!-- 指定job的分組 -->
        <property name="group" value="job_group1"/>
        <!-- 指定具體的job類 -->
        <property name="jobClass" value="com.qf.quartz.MyJob"/>
    </bean>

    <!-- 2:定義觸發(fā)器的bean,定義一個(gè)Cron的Trigger,一個(gè)觸發(fā)器只能和一個(gè)任務(wù)進(jìn)行綁定 -->
    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!-- 指定Trigger的名稱 -->
        <property name="name" value="trigger1"/>
        <!-- 指定Trigger的名稱 -->
        <property name="group" value="trigger_group1"/>
        <!-- 指定Tirgger綁定的JobDetail -->
        <property name="jobDetail" ref="lxJob"/>
        <!-- 指定Cron 的表達(dá)式 ,當(dāng)前是每隔5s運(yùn)行一次 -->
        <property name="cronExpression" value="*/5 * * * * ?" />
    </bean>

    <!-- 3.定義調(diào)度器,并將Trigger注冊到調(diào)度器中 -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="cronTrigger"/>
            </list>
        </property>
        <!-- 添加 quartz 配置,如下兩種方式均可 -->
        <!--<property name="configLocation" value="classpath:quartz.properties"></property>-->
        <property name="quartzProperties">
            <value>
                # 指定調(diào)度器名稱,實(shí)際類型為:QuartzScheduler
                org.quartz.scheduler.instanceName = MyScheduler
                # 指定連接池
                org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
                # 連接池線程數(shù)量
                org.quartz.threadPool.threadCount = 11
                # 優(yōu)先級
                org.quartz.threadPool.threadPriority = 5
                # 不持久化job
                org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
            </value>
        </property>
    </bean>
</beans>

4.4 操作

4.4.1 啟動任務(wù)

工廠啟動,調(diào)度器啟動,任務(wù)調(diào)度開始

public static void main(String[] args) throws InterruptedException, SchedulerException {    
    // 工廠啟動,任務(wù)啟動,工廠關(guān)閉,任務(wù)停止
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
4.4.2 任務(wù)操作
4.4.2.1 刪除任務(wù)
public static void main(String[] args) throws InterruptedException, SchedulerException {        
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    System.out.println("=============");
    StdScheduler scheduler = (StdScheduler) context.getBean("scheduler");
    System.out.println(scheduler.getClass());
    Thread.sleep(3000);
    // 刪除Job
    scheduler.deleteJob(JobKey.jobKey("job1","job_group1"));
}
4.4.2.2 暫停、恢復(fù)
public static void main(String[] args) throws InterruptedException, SchedulerException {        
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    System.out.println("=============");
    StdScheduler scheduler = (StdScheduler) context.getBean("scheduler");
    System.out.println(scheduler.getClass());
    Thread.sleep(3000);
    // 暫停,恢復(fù)工作
    scheduler.pauseJob(JobKey.jobKey("job1","job_group1"));// 暫停工作
    Thread.sleep(3000);
    scheduler.resumeJob(JobKey.jobKey("job1","job_group1"));// 恢復(fù)工作
}
4.4.2.3 批量操作
public static void main(String[] args) throws InterruptedException, SchedulerException {        
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    System.out.println("=============");
    StdScheduler scheduler = (StdScheduler) context.getBean("scheduler");
    System.out.println(scheduler.getClass());
    Thread.sleep(3000);
    GroupMatcher<JobKey> group1 = GroupMatcher.groupEquals("job_group1");
    scheduler.pauseJobs(group1); // 暫停組中所有工作
    Thread.sleep(2000);
    scheduler.resumeJobs(group1); // 恢復(fù)組中所有工作 
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容