Quartz入门学习

Quartz入门学习

一, Quartz介紹

Quartz是一個完全由Java編寫的開源作業調度框架, 為在Java應用程序中進行作業調度提供簡單卻強大的機制. Quartz允許程序開發人員根據時間的間隔來調度作業, 它實現了作業和觸發器的多懟多的關係, 還能把多個作業與不同的觸發器關聯.

1.1 Quartz核心概念

  • Job : 表示一個工作, 要執行的具體內容, 此接口中只有一個方法

    void execute(JobExecutionContext context)
    
  • JobDetail : 表示一個具體的可執行的調度程序, Job是這個可執行調度程序所要執行的內容, 另外JobDetail還包含了這個任務調度的方案和策略.

  • Trigger : 代表一個調度參數的配置, 什麼時候去調

  • Scheduler : 代表一個調度容器, 一個調度容器中可以註冊多個JobDetail和Trigger. 當Trigger於JobDetail組合, 就可以被Scheduler容器調度了.

1.2 Quartz API

Quartz API的關鍵接口是:

  • Scheduler: 於調度程序交互的主要API.
  • Job : 調度器執行的任務組件需要實現的接口
  • JobDetail : 用於定義作業的實例.
  • Trigger(即觸發器) : 定義執行給定作業的計劃的組件.
  • JobBuilder : 用於定義/構建JobDetail實例, 用於定義作業的實例.
  • TriggerBuilder : 用於定義/構建觸發器實例.

​ Scheduler的生命期, 從SchedulerFactory創建它時開始, 到Scheduler調用shutdown()方法時結束; Scheduler被創建後, 可以增加, 刪除和列舉Job和Trigger, 以及執行其他與調度相關的操作(如暫停Trigger). 但是, Scheduler只有在調用start()方法後, 才會真正地觸發trigger(即執行job).

​ Trigger用於觸發job的執行, 最常用的主要是SimpleTrigger和CronTrigger.

  • SimpleTrigger主要用於一次性執行的job(只在某個特定的時間點執行一次), 或者job在特定的時間點執行, 重複執行N次, 每次執行間隔T個時間單位
  • CronTrigger使用了cron, 在基於日曆的調度上非常有用.

1.3 Job和JobDetail

我们在創建JobDetail時, 將要執行的job的類名會傳給JobDetail, scheduler就知道了要執行何種類型的job. 每次當scheduler執行job時, 在調用其execute()方法之前會創建該類的一個新的實例.

當一個trigger被觸發時, 與之關聯的JobDetail實例會被加載, JobDetail引用的job類通過配置在Scheduler上的JobFactory進行初始化. 默認的JobFactory實現, 僅僅是調用job類的newInstance()方法, 然後嘗試調用JobDataMap中的key的setter方法.

二, 簡單定時任務實例

2.1 普通Demo

定義任務類MyJob

package com.lmc.quartz;

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


/**
 * @author: lmc
 * @Description: 任務類
 * @version: 1.0
 * @date: 2020/9/16 17:07
 */
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        Object tv1 = jobExecutionContext.getTrigger().getJobDataMap().get("t1");
        Object jv1 = jobExecutionContext.getJobDetail().getJobDataMap().get("j1");
        Object sv1 = null;
        try {
            sv1 = jobExecutionContext.getScheduler().getContext().get("skey");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        System.out.println("===============================任務正在進行" + System.currentTimeMillis() + "==============================");
        System.out.println("tv1 = " + tv1);
        System.out.println("jv1 = " + jv1);
        System.out.println("sv1 = " + sv1);
    }
}

主類:

package com.lmc.quartz;

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

/**
 * @author: Test
 * @Description: 描述信息
 * @version: 1.0
 * @date: 2020/9/16 17:22
 */
public class Test {
    public static void main(String[] args) throws SchedulerException {
        //創建一個scheduler
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.getContext().put("skey", "svalue");
        //創建一個trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                            .withIdentity("trigger1", "group1").usingJobData("t1", "tv1")
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).repeatForever())
                            .build();
        trigger.getJobDataMap().put("t2", "tv2");
        //創建一個job
        JobDetail job = JobBuilder.newJob(MyJob.class)
                        .usingJobData("j1", "jv1")
                        .withIdentity("myjob", "mygroup")
                        .build();
        job.getJobDataMap().put("j2", "jv2");
        //註冊trigger並啟動scheduler
        scheduler.scheduleJob(job, trigger);
        scheduler.start();
    }
}

2.2 Boot

Quartz配置類 :

package com.lmc.quartz;

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Date;

/**
 * @author: QuartzConfig
 * @Description: quartz配置類
 * @version: 1.0
 * @date: 2020/9/18 9:10
 */
@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail getJobDetail() {
        return JobBuilder.newJob(MyJob.class)
                        .withDescription("this is a job")
                        .withIdentity("job1", "jGroup1")
                        .storeDurably().build();
    }
    
    @Bean
    public Trigger getTrigger() {
        CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule("0 0 29 8 * * ?");
        return TriggerBuilder.newTrigger().forJob(getJobDetail())
                                        .withDescription("this is a trigger")
                                        .withIdentity("trigger1", "Group1")
                                        .startAt(new Date())
                                        .withSchedule(builder)
                                        .build();
    }
}

啟動類 :

package com.lmc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class EurekaProviderApplication8001 {

    public static void main(String[] args) {
        SpringApplication.run(EurekaProviderApplication8001.class, args);
    }
}

三, Trigger

Trigger用於觸發job的執行, Quartz中有五種類型的Trigger :SimpleTrigger, CronTrigger, DateIntervalTrigger, NthIncludedDayTrigger和Calendar類. 最常用的主要是SimpleTrigger和CronTrigger.

trigger屬性:

  • jobKey : 當trigger觸發時被執行的job的身份;
  • startTime : 設置trigger第一次觸發的時間, 該屬性的值是Date類型, 表示某個指定的時間點; 有些類型的trigger, 會在設置的startTime時立刻觸發, 有些類型的trigger, 表示其觸發是在startTime之後開始生效.
  • endTime :表示trigger失效的時間點
  • priority : 優先級. Quartz如果沒有足夠的資源同時觸發所有的trigger, 這種情況下, 可以控制哪些trigger優先使用Quartz的工作線程.

3.1 SimpleTrigger

SimpleTrigger可以滿足的調度需求是 : 在具體的時間點執行一次, 或者在具體的時間點執行, 並且以指定的間隔重複執行若干次. SimpleTrigger的屬性包括 : 開始時間, 結束時間, 重複次數以及重複的間隔. 重複次數, 可以是0, 正整數, 以及常量SimpleTrigger.REPEAT_INDEFINTELY. 重複的間隔, 必須是0, 或者long型的正數, 表示毫秒. 如果重複間隔為0, trigger將會以重複次數並發執行

指定時間開始觸發, 只執行一次, 不重複

SimpleTrigger trigger = (SimpleTrigger) newTrigger()
                                    .withIdentity("trigger1", "group1")
                                    .usingJobData("t1", "tv1")
    								//指定時間觸發
                                    .startAt(futureDate(5, IntervalUnit.MINUTE)) 
                                    .forJob("job1", "group")
                                    .build();

指定時間觸發, 重複執行

SimpleTrigger trigger = (SimpleTrigger) newTrigger()
                                    .withIdentity("trigger1", "group1")
    								//5分鐘後觸發
                                    .startAt(futureDate(5, IntervalUnit.MINUTE))
                                    //每10秒執行一次, 執行10次
                    .withSchedule(simpleSchedule().withIntervalInSeconds(10).withRepeatCount(10))
                                    .forJob("job1", "group")
                                    .build();

立即觸發, 重複執行, 直到某一時間

SimpleTrigger trigger = (SimpleTrigger) newTrigger()
                                    .withIdentity("trigger1", "group1")
                                    //每10秒執行一次, 執行10次
                                    .withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever())
    								//22:00停止執行
    								.endAt(dateOf(22, 0, 0))
                                    .forJob("job1", "group")
                                    .build();

在下一個小時的整點觸發, 重複執行

SimpleTrigger trigger = (SimpleTrigger) newTrigger()
                                    .withIdentity("trigger1", "group1")
                                    //下一小時整點觸發
                                    .startAt(evenHourDate(null))    .withSchedule(simpleSchedule().withIntervalInHours(1).repeatForever())
                                    .build();

3.2 CronTrigger

CronTrigger觸發器可以像日曆那樣按日程觸發任務, 是一個基於日曆的作業調度器.

cron表達式: 用來配置CronTrigger實例, 由七個部分組成

位置時間域允許值
10-59
2分鐘0-59
3小時0-23
4日期1-31
5月份1-12
6星期1-7
7年份(可選)

特殊符號 :

特殊符號含義
*用來表示域中"每個"可能的值
?表示不指定值, 使用的場景為不需要當前設置這個字段的值. 例如"月份的日期" 和"星期中的日期"
-表示區間
,表示指定多個值
/表示值的增量, 例如分鐘域寫入’0/15’, 表示"每隔15分鐘, 從0開始"
L'last’的縮寫

代碼實現:

CronTrigger trigger = newTrigger()
                    .withIdentity("trigger1", "group1")
                    .withSchedule(cronSchedule("0 0 29 8 * * ?"))
                    .forJob("job1", "group")
                    .build();

四, Listener

4.1 JobListener

任務監聽器需要實現JobListener接口

package com.lmc.quartz;

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

/**
 * @author: MyJobListener
 * @Description: 描述信息
 * @version: 1.0
 * @date: 2020/9/17 15:37
 */
public class MyJobListener implements JobListener {
    @Override
    public String getName() {
        return "myJobListener";
    }

    /**
     * 任務執行之前執行
     * @param jobExecutionContext
     */
    @Override
    public void jobToBeExecuted(JobExecutionContext jobExecutionContext) {
        System.out.println("=====================任務即將開始" + System.currentTimeMillis() + "=====================");
    }

    /**
     * 這個方法正常情況下不執行, 但是如果當TriggerListener中的vetoJobExecution方法返回true時, 就執行這個方法
     * @param jobExecutionContext
     */
    @Override
    public void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {

    }

    /**
     * 任務執行完成後執行
     * @param jobExecutionContext
     * @param e
     */
    @Override
    public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {
        System.out.println("=====================任務已完成" + System.currentTimeMillis() + "======================");
    }
}

方法解釋 :

  • getName() : 指定監聽器名稱
  • jobToBeExecuted() : 任務執行之前調用
  • jobWasExecuted() : 任務執行完成後調用

4.2 TriggerListener

trigger監聽器要實現TriggerListener接口

package com.lmc.quartz;

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

/**
 * @author: MyTriggerListener
 * @Description: 描述信息
 * @version: 1.0
 * @date: 2020/9/17 16:15
 */
public class MyTriggerListener implements TriggerListener {
    @Override
    public String getName() {
        return "myTriggerListener";
    }

    /**
     * Trigger被激發, 它關聯的job即將被運行
     * @param trigger
     * @param jobExecutionContext
     */
    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
        System.err.println("triggerFired");
    }

    /**
     * Trigger被激發, 它關聯的job即將被運行, 先執行triggerFired
     * @param trigger
     * @param jobExecutionContext
     * @return
     */
    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
        System.err.println("vetoJobExecution");
        return false;
    }

    /**
     * 當trigger錯過被激發時執行, 比如當前時間有很多觸發器都需要執行, 但是線程池中數量有限, 那麼有的觸發器就有可能超時, 錯過這一輪的觸發
     * @param trigger
     */
    @Override
    public void triggerMisfired(Trigger trigger) {
        System.err.println("triggerMisfired");
    }

    /**
     * 任務完成時觸發
     * @param trigger
     * @param jobExecutionContext
     * @param completedExecutionInstruction
     */
    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
        System.err.println("triggerComplete");
    }
}

方法解釋 :

  • getName : 指定觸發器名稱
  • triggerFired : Trigger被激發, 它關聯的job即將被運行
  • vetoJobExecution : Trigger被激發, 它關聯的job即將被運行, 先執行triggerFired
  • triggerMisfired : 當trigger錯過被激發時執行, 比如當前時間有很多觸發器都需要執行, 但是線程池中數量有限, 那麼有的觸發器就有可能超時, 錯過這一輪的觸發
  • triggerComplete : 任務完成時觸發

4.3 SchedulerListener

SchedulerListener非常類似於TriggerListener和JobListener.它包括了: 添加job/trigger, 刪除job/trigger, 調度程序中的嚴重錯誤, 關閉調度程序通知等.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值