Quartz學習

Quartz學習

1.Quartz CronTrigger 最完整配置說明

CronTrigger配置格式:html

格式: [秒] [分] [小時] [日] [月] [周] [年]java

序號 說明 是否必填 容許填寫的值 容許的通配符
1 0-59 , - * /
2 0-59 , - * /
3 小時 0-23 , - * /
4 1-31 , - * ? / L W
5 1-12 or JAN-DEC , - * /
6 1-7 or SUN-SAT , - * ? / L #
7 empty 或 1970-2099 , - * /

通配符說明:服務器

* 表示全部值. 例如:在分的字段上設置 "*",表示每一分鐘都會觸發。併發

? 表示不指定值。使用的場景爲不須要關心當前設置這個字段的值。例如:要在每個月的10號觸發一個操做,但不關心是周幾,因此須要周位置的那個字段設置爲"?" 具體設置爲 0 0 0 10 * ?框架

- 表示區間。例如 在小時上設置 "10-12",表示 10,11,12點都會觸發。ide

, 表示指定多個值,例如在周字段上設置 "MON,WED,FRI" 表示週一,週三和週五觸發學習

/ 用於遞增觸發。如在秒上面設置"5/15" 表示從5秒開始,每增15秒觸發(5,20,35,50)。 在月字段上設置'1/3'所示每個月1號開始,每隔三天觸發一次。測試

L 表示最後的意思。在日字段設置上,表示當月的最後一天(依據當前月份,若是是二月還會依據是不是潤年[leap]), 在周字段上表示星期六,至關於"7"或"SAT"。若是在"L"前加上數字,則表示該數據的最後一個。例如在周字段上設置"6L"這樣的格式,則表示「本月最後一個星期五" ui

W 表示離指定日期的最近那個工做日(週一至週五). 例如在日字段上設置"15W",表示離每個月15號最近的那個工做日觸發。若是15號正好是週六,則找最近的週五(14號)觸發, 若是15號是周未,則找最近的下週一(16號)觸發.若是15號正好在工做日(週一至週五),則就在該天觸發。若是指定格式爲 "1W",它則表示每個月1號日後最近的工做日觸發。若是1號正是週六,則將在3號下週一觸發。(注,"W"前只能設置具體的數字,不容許區間"-").this

# 序號(表示每個月的第幾個周幾),例如在周字段上設置"6#3"表示在每個月的第三個週六.注意若是指定"#5",正好第五週沒有周六,則不會觸發該配置(用在母親節和父親節再合適不過了)

<br/>

Quartz Scheduler 任務參數與任務狀態

@DisallowConcurrentExecution (簡單來講:不容許任務還沒結束,新開線程執行任務)

此標記用在實現Job的類上面,意思是不容許併發執行,按照我以前的理解是 不容許調度框架在同一時刻調用Job類,後來通過測試發現並非這樣,而是Job(任務)的執行時間[好比須要10秒]大於任務的時間間隔[Interval(5秒)],那麼默認狀況下,調度框架爲了能讓 任務按照咱們預約的時間間隔執行,會立刻啓用新的線程執行任務。不然的話會等待任務執行完畢之後 再從新執行!(這樣會致使任務的執行不是按照咱們預先定義的時間間隔執行)

測試代碼,這是官方提供的例子。設定的時間間隔爲3秒,但job執行時間是5秒,設置@DisallowConcurrentExecution之後程序會等任務執行完畢之後再去執行,不然會在3秒時再啓用新的線程執行

org.quartz.threadPool.threadCount = 5 這裏配置框架的線程池中線程的數量,要多配置幾個,不然@DisallowConcurrentExecution不起做用

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 5
org.quartz.jobStore.class =org.quartz.simpl.RAMJobStore
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class StatefulDumbJob implements Job {

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Constants.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    public static final String NUM_EXECUTIONS = "NumExecutions";

    public static final String EXECUTION_DELAY = "ExecutionDelay";

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Constructors.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    public StatefulDumbJob() {
    }

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Interface.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    /**
     * <p>
     * Called by the <code>{@link org.quartz.Scheduler}</code> when a <code>{@link org.quartz.Trigger}</code>
     * fires that is associated with the <code>Job</code>.
     * </p>
     * 
     * @throws JobExecutionException
     *           if there is an exception while executing the job.
     */
    public void execute(JobExecutionContext context)
        throws JobExecutionException {
        System.err.println("---" + context.getJobDetail().getKey()
                + " executing.[" + new Date() + "]");

        JobDataMap map = context.getJobDetail().getJobDataMap();

        int executeCount = 0;
        if (map.containsKey(NUM_EXECUTIONS)) {
            executeCount = map.getInt(NUM_EXECUTIONS);
        }

        executeCount++;

        map.put(NUM_EXECUTIONS, executeCount);

        long delay = 5000l;
        if (map.containsKey(EXECUTION_DELAY)) {
            delay = map.getLong(EXECUTION_DELAY);
        }

        try {
            Thread.sleep(delay);
        } catch (Exception ignore) {
        }

        System.err.println("  -" + context.getJobDetail().getKey()
                + " complete (" + executeCount + ").");

    }

}
public class MisfireExample {

    
    public void run() throws Exception {
        Logger log = LoggerFactory.getLogger(MisfireExample.class);

        log.info("------- Initializing -------------------");

        // First we must get a reference to a scheduler
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        log.info("------- Initialization Complete -----------");

        log.info("------- Scheduling Jobs -----------");

        // jobs can be scheduled before start() has been called

        // get a "nice round" time a few seconds in the future...
        Date startTime = nextGivenSecondDate(null, 15);

        // statefulJob1 will run every three seconds
        // (but it will delay for ten seconds)
        JobDetail job = newJob(StatefulDumbJob.class)
            .withIdentity("statefulJob1", "group1")
            .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L)
            .build();
    
        SimpleTrigger trigger = newTrigger() 
            .withIdentity("trigger1", "group1")
            .startAt(startTime)
            .withSchedule(simpleSchedule()
                    .withIntervalInSeconds(3)
                    .repeatForever())
            .build();
        
        Date ft = sched.scheduleJob(job, trigger);
        log.info(job.getKey() +
                " will run at: " + ft +  
                " and repeat: " + trigger.getRepeatCount() + 
                " times, every " + trigger.getRepeatInterval() / 1000 + " seconds");

        log.info("------- Starting Scheduler ----------------");

        // jobs don't start firing until start() has been called...
        sched.start();

        log.info("------- Started Scheduler -----------------");
        
        try {
            // sleep for ten minutes for triggers to file....
            Thread.sleep(600L * 1000L); 
        } catch (Exception e) {
        }

        log.info("------- Shutting Down ---------------------");

        sched.shutdown(true);

        log.info("------- Shutdown Complete -----------------");

        SchedulerMetaData metaData = sched.getMetaData();
        log.info("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");
    }



    public static void main(String[] args) throws Exception {

        MisfireExample example = new MisfireExample();
        example.run();
    }

}

@PersistJobDataAfterExecution

此標記說明在執行完Job的execution方法後保存JobDataMap當中固定數據,在默認狀況下 也就是沒有設置 @PersistJobDataAfterExecution的時候 每一個job都擁有獨立JobDataMap

不然改任務在重複執行的時候具備相同的JobDataMap

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class BadJob1 implements Job {

    public BadJob1() {
    }

    public void execute(JobExecutionContext context)
        throws JobExecutionException {
        JobKey jobKey = context.getJobDetail().getKey();
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();
        
        int denominator = dataMap.getInt("denominator");
        System.out.println("---" + jobKey + " executing at " + new Date() + " with denominator " + denominator);

        denominator++;
        dataMap.put("denominator", denominator);
    }

}
public class JobExceptionExample {

    public void run() throws Exception {

        // First we must get a reference to a scheduler
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        // jobs can be scheduled before start() has been called

        // get a "nice round" time a few seconds in the future...
        Date startTime = nextGivenSecondDate(null, 2);

        JobDetail job = newJob(BadJob1.class)
            .withIdentity("badJob1", "group1")
            .usingJobData("denominator", "0")
            .build();
        
        SimpleTrigger trigger = newTrigger() 
            .withIdentity("trigger1", "group1")
            .startAt(startTime)
            .withSchedule(simpleSchedule()
                    .withIntervalInSeconds(2)
                    .repeatForever())
            .build();

        Date ft = sched.scheduleJob(job, trigger);
        
        //任務每2秒執行一次 那麼在BadJob1的方法中拿到的JobDataMap的數據是共享的.
        //這裏要注意一個狀況: 就是JobDataMap的數據共享只針對一個BadJob1任務。
        //若是在下面在新增長一個任務 那麼他們之間是不共享的 好比下面
        
        JobDetail job2 = newJob(BadJob1.class)
                .withIdentity("badJob1", "group1")
                .usingJobData("denominator", "0")
                .build();
        
        SimpleTrigger trigger2 = newTrigger() 
                .withIdentity("trigger1", "group1")
                .startAt(startTime)
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())
                .build();
        
        //這個job2與job執行的JobDataMap不共享
        sched.scheduleJob(job2, trigger2);
        
        sched.start();

        try {
            // sleep for 30 seconds
            Thread.sleep(30L * 1000L);
        } catch (Exception e) {
        }

        sched.shutdown(false);
    }

    public static void main(String[] args) throws Exception {

        JobExceptionExample example = new JobExceptionExample();
        example.run();
    }

}

requestRecovery的意思是當任務在執行過程當中出現意外 好比服務器down了 那麼在重啓時候是否恢復任務

JobDetail job = newJob(HelloJob.class)
    .withIdentity("job1", "group1")
    .storeDurably() 
    .requestRecovery()
    .build();

<br/>

Quartz Scheduler當任務中出現異常時的處理策略(JobExecutionExceptions)

問題1 若是任務執行發生錯誤了怎麼辦!
Quartz提供了二種解決方法:

  • 1 當即從新執行任務
  • 2 當即中止全部相關這個任務的觸發器

問題2 怎麼去執行呢?
Quartz的解決方式是:在你的程序出錯時,用Quartz提供的JobExecutionException類相關方法很好的解決
1、當即從新執行該任務

當任務中出現異常時,咱們捕獲它,而後轉換爲JobExecutionExceptions異常拋出,同時能夠控制調度引擎當即從新執行這個任務。

try {
        int zero = 0;
        int calculation = 4815 / zero;
    } 
    catch (Exception e) {
        _log.info("--- Error in job!");
        JobExecutionException e2 = 
            new JobExecutionException(e);
        // this job will refire immediately
        e2.refireImmediately();
        throw e2;
    }

2、取消全部與這個任務關聯的觸發器

try {
    int zero = 0;
    int calculation = 4815 / zero;
} 
catch (Exception e) {
    _log.info("--- Error in job!");
    JobExecutionException e2 = 
        new JobExecutionException(e);
    // Quartz will automatically unschedule
    // all triggers associated with this job
    // so that it does not run again
    e2.setUnscheduleAllTriggers(true);
    throw e2;
}

<br/>

Quartz Scheduler與Spring集成(一) 基礎配置與常見問題

https://www.cnblogs.com/daxin...

經常使用操做代碼:
http://www.quartz-scheduler.o...

<br/>

Quartz How-To:Defining a Job (with input data)

Job:

public class PrintPropsJob implements Job {

    public PrintPropsJob() {
        // Instances of Job must have a public no-argument constructor.
    }

    public void execute(JobExecutionContext context)
            throws JobExecutionException {

        JobDataMap data = context.getMergedJobDataMap();
        System.out.println("someProp = " + data.getString("someProp"));
    }

}

Define job instance:

JobDetail job1 = newJob(MyJobClass.class)
    .withIdentity("job1", "group1")        //標識任務
    .usingJobData("someProp", "someValue")        //input data 
    .build();

<br/>

Quartz How-To: Scheduling a Job

// Define job instance
JobDetail job1 = newJob(ColorJob.class)
    .withIdentity("job1", "group1")
    .build();

// Define a Trigger that will fire "now", and not repeat
Trigger trigger = newTrigger()
    .withIdentity("trigger1", "group1")
    .startNow()
    .build();

// Schedule the job with the trigger
sched.scheduleJob(job, trigger);

<br/>

How-To: Update an existing job

// Add the new job to the scheduler, instructing it to "replace"
//  the existing job with the given name and group (if any)
JobDetail job1 = newJob(MyJobClass.class)
    .withIdentity("job1", "group1")
    .build();

// store, and set overwrite flag to 'true'     
scheduler.addJob(job1, true);

<br/>

How-To: Updating a trigger

有一些業務場景,咱們須要手動去更新任務的觸發時間,好比某個任務是每隔10分鐘觸發一次,如今須要改爲每隔20分鐘觸發一次,這樣既就須要手動的更新觸發器
官方的例子:
http://www.quartz-scheduler.o...

Replacing a trigger 替換觸發器,經過triggerkey移除舊的觸發器,同時添加一個新的進去。

// Define a new Trigger 
Trigger trigger = newTrigger()
    .withIdentity("newTrigger", "group1")
    .startNow()
    .build();

// tell the scheduler to remove the old trigger with the given key, and put the new one in its place
sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger);

可是有一個地方須要注意:sched.rescheduleJob(triggerKey("oldTrigger", "group1"), trigger); 這個方法返回一個Date.

若是返回 null 說明替換失敗,緣由就是舊觸發器沒有找到,因此新的觸發器也不會設置進去.

<br/>

How-To: Using Job Listeners

Quartz Scheduler 能夠對Job(任務)創建一個監聽器,分別對任務執行 以前-以後-取消 3個狀態進行監聽。

實現監聽器須要實現JobListener接口,而後註冊到Scheduler上就能夠了。

一:首先寫一個監聽器實現類

package com.gary.operation.jobdemo.example1;

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

public class MyJobListener implements JobListener {

    @Override
    public String getName() {
        return "MyJobListener";
    }

    /**
     * (1)
     * 任務執行以前執行
     * Called by the Scheduler when a JobDetail is about to be executed (an associated Trigger has occurred).
     */
    @Override
    public void jobToBeExecuted(JobExecutionContext context) {
        System.out.println("MyJobListener.jobToBeExecuted()");
    }

    /**
     * (2)
     * 這個方法正常狀況下不執行,可是若是當TriggerListener中的vetoJobExecution方法返回true時,那麼執行這個方法.
     * 須要注意的是 若是方法(2)執行 那麼(1),(3)這個倆個方法不會執行,由於任務被終止了嘛.
     * Called by the Scheduler when a JobDetail was about to be executed (an associated Trigger has occurred),
     * but a TriggerListener vetoed it's execution.
     */
    @Override
    public void jobExecutionVetoed(JobExecutionContext context) {
        System.out.println("MyJobListener.jobExecutionVetoed()");
    }

    /**
     * (3)
     * 任務執行完成後執行,jobException若是它不爲空則說明任務在執行過程當中出現了異常
     * Called by the Scheduler after a JobDetail has been executed, and be for the associated Trigger's triggered(xx) method has been called.
     */
    @Override
    public void jobWasExecuted(JobExecutionContext context,
            JobExecutionException jobException) {
        System.out.println("MyJobListener.jobWasExecuted()");
    }

}

二:將這個監聽器註冊到Scheduler
假設有一個任務的key是 job1與 group1

// define the job and tie it to our HelloJob class
        JobDetail job = newJob(HelloJob.class)
            .withIdentity("job1", "group1")
            .build();
全局註冊,全部Job都會起做用
Registering A JobListener With The Scheduler To Listen To All Jobs
sched.getListenerManager().addJobListener(new MyJobListener());
指定具體的任務
Registering A JobListener With The Scheduler To Listen To A Specific Job
Matcher<JobKey> matcher = KeyMatcher.keyEquals(new JobKey("job1", "group1"));
sched.getListenerManager().addJobListener(new MyJobListener(), matcher);
指定一組任務
Registering A JobListener With The Scheduler To Listen To All Jobs In a Group
GroupMatcher<JobKey> matcher = GroupMatcher.jobGroupEquals("group1");
sched.getListenerManager().addJobListener(new MyJobListener(), matcher);
能夠根據組的名字匹配開頭和結尾或包含
GroupMatcher<JobKey> matcher = GroupMatcher.groupStartsWith("g");
GroupMatcher<JobKey> matcher = GroupMatcher.groupContains("g");
sched.getListenerManager().addJobListener(new MyJobListener(), matcher);

<br/>

How-To: Trigger That Executes Every Day

Using CronTrigger

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startNow()
    .withSchedule(dailyAtHourAndMinute(15, 0)) // fire every day at 15:00
    .build();

Using SimpleTrigger

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startAt(tomorrowAt(15, 0, 0)  // first fire time 15:00:00 tomorrow
    .withSchedule(simpleSchedule()
            .withIntervalInHours(24) // interval is actually set at 24 hours' worth of milliseconds
            .repeatForever())
    .build();

Using CalendarIntervalTrigger

trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startAt(tomorrowAt(15, 0, 0)  // 15:00:00 tomorrow
    .withSchedule(calendarIntervalSchedule()
            .withIntervalInDays(1)) // interval is set in calendar days
    .build();

<br/>

Quartz Trigger Priority 觸發器優先級

當多個觸發器在一個相同的時間內觸發,而且調度引擎中的資源有限的狀況下,那麼具備較高優先級的觸發器先觸發。

須要將配置文件中的org.quartz.threadPool.threadCount = 1設置爲1,這樣能更好的測試出效果。

package com.gary.operation.jobdemo.example14;

import static org.quartz.DateBuilder.futureDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

import java.util.Date;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PriorityExample {
    
    public void run() throws Exception {
        Logger log = LoggerFactory.getLogger(PriorityExample.class);

        // First we must get a reference to a scheduler
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        JobDetail job = newJob(TriggerEchoJob.class)
            .withIdentity("TriggerEchoJob")
            .build();
            
        Date startTime = futureDate(5, IntervalUnit.SECOND);
        
        Trigger trigger1 = newTrigger()
            .withIdentity("Priority7 Trigger5SecondRepeat")
            .startAt(startTime)
            .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5))
            .withPriority(7)
            .forJob(job)
            .build();

        Trigger trigger2 = newTrigger()
            .withIdentity("Priority5 Trigger10SecondRepeat")
            .startAt(startTime)
            .withPriority(5)
            .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5))
            .forJob(job)
            .build();
        
        Trigger trigger3 = newTrigger()
            .withIdentity("Priority10 Trigger15SecondRepeat")
            .startAt(startTime)
            .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5))
            .withPriority(10)
            .forJob(job)
            .build();

        // Tell quartz to schedule the job using our trigger
        sched.scheduleJob(job, trigger1);
        sched.scheduleJob(trigger2);
        sched.scheduleJob(trigger3);

        sched.start();

        log.info("------- Waiting 30 seconds... -------------");
        try {
            Thread.sleep(30L * 1000L); 
            // executing...
        } catch (Exception e) {
        }

        sched.shutdown(true);
    }

    public static void main(String[] args) throws Exception {
        PriorityExample example = new PriorityExample();
        example.run();
    }
}

(筆記內容大部分來源: https://www.cnblogs.com/daxin...

相關文章
相關標籤/搜索