springboot 整合quartz (二):jobDataMap和trigger

jobDataMap

jobDataMap能夠用來裝載可序列化的對象,用於在job執行的時候獲取。html

注:jobDetailtrigger中均可以添加jobDataMap,後面的對象會把前面對象相同鍵值對象的值覆蓋java

job實體類建立代碼(建立job示例,添加jobDataMap)api

public static void main(String[] args) throws SchedulerException, ParseException {
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.start();

        // 定義job,綁定咱們的定時任務
        JobDetail job2 = newJob(HelloJob.class)
                .usingJobData("name", "李四")
                .usingJobData("characteristic", "22")
                .build();

        // 執行任務,用定義好的觸發器 和 任務
        scheduler.scheduleJob(job2, getTrigger1());

    }

job類代碼(job運行示例,獲取jobDataMap)服務器

public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();

        String name = jobDataMap.get("name").toString();
        String characteristic = jobDataMap.get("characteristic").toString();

        JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
        String mergedName = mergedJobDataMap.getString("name");

        System.out.println("name : " + name);
        System.out.println("mergedName:" + mergedName);

        System.out.println("characteristic : " + characteristic);

    }

trigger併發

/**
     * 觸發器當即觸發,而後每隔2秒 觸發一次,22:55:00:
     */
    private static SimpleTrigger getTrigger1() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

        //定義一個任務觸發器
        return TriggerBuilder.newTrigger()
                .withIdentity("job2", "group2")
                //定點觸發
                //.startAt(sdf.parse("2018-09-27 10:27:00"))
                // 五秒鐘後觸發
                .startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND))
                .withSchedule(
                        simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever()
                        //.withRepeatCount(0)
                )
                .usingJobData("name",",,")
                //.endAt(DateBuilder.dateOf(22, 55, 0))
                .build();
    }

測試結果:測試

name : 李四
mergedName:,,
characteristic : 22

trigger

trigger是觸發器,任務什麼時候運行、運行幾回,它說了算。ui

TriggerKey

  • TriggerKey:triggerKey是全部觸發器的標識信息。
  • JobKey: job示例的表示信息,觸發器被觸發時,該指定的job示例會運行

TriggerKey介紹

設置TriggerKey能夠經過JobBuilder的.withIdentity() 進行設置,以下:默認api提供三種方式 <img src="https://ws3.sinaimg.cn/mw690/005AQjvJly1fw41dc8fvjj30s608wq4z.jpg" alt="image">this

全參數的源碼以下:code

public TriggerBuilder<T> withIdentity(String name, String group) {
        key = new TriggerKey(name, group);
        return this;
}

注:name屬性是必填的,group不寫,默認值爲:defaultorm

JobKey大同小異,不予介紹。

其餘通用屬性

  • startTime:啓動時間,默認當前時間,當即執行
  • endTime:自行設置,默認爲空
  • priority: 優先級,默認爲5,用於多個Trigger併發執行。

simpleTrigger

使用場景:在一個指定時間段內執行一次做業任務或是在指定的時間間隔內屢次執行做業任務,SimpleTrigger應該能知足你的調度需求。

例如:

  • 你但願觸發器在2015年1月13日上午11:23:54準時觸發,或是但願在那個時間點觸發,而後再重複觸發5次,每隔10秒一次。

使用案例:

  • 觸發器 2018-09-27 10:27:00 定點觸發,重複0次
private static SimpleTrigger getTrigger2() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        //定義一個任務觸發器
        return newTrigger()
                .withIdentity("job1", "group1")
                //定點觸發
                .startAt(sdf.parse("2018-09-27 10:27:00"))
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(2)

                        .withRepeatCount(0)
                ).build();

 }

注:startAt中的日期可使用DateBuilder,示例,在指定時間延遲5秒執行

.startAt(DateBuilder.futureDate(5, DateBuilder.IntervalUnit.SECOND))

觸發失敗指令(待完善。。。)

執行常量以下:

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY  
MISFIRE_INSTRUCTION_FIRE_NOW  
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT  
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT  
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT  
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

觸發指令設置

withMisfireHandlingInstructionFireNow
——以當前時間爲觸發頻率當即觸發執行
——執行至FinalTIme的剩餘週期次數
——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值

withMisfireHandlingInstructionIgnoreMisfires
——以錯過的第一個頻率時間馬上開始執行
——重作錯過的全部頻率週期
——當下一次觸發頻率發生時間大於當前時間之後,按照Interval的依次執行剩下的頻率
——共執行RepeatCount+1次

withMisfireHandlingInstructionNextWithExistingCount
——不觸發當即執行
——等待下次觸發頻率週期時刻,執行至FinalTime的剩餘週期次數
——以startTime爲基準計算週期頻率,並獲得FinalTime
——即便中間出現pause,resume之後保持FinalTime時間不變


withMisfireHandlingInstructionNowWithExistingCount
——以當前時間爲觸發頻率當即觸發執行
——執行至FinalTIme的剩餘週期次數
——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值

withMisfireHandlingInstructionNextWithRemainingCount
——不觸發當即執行
——等待下次觸發頻率週期時刻,執行至FinalTime的剩餘週期次數
——以startTime爲基準計算週期頻率,並獲得FinalTime
——即便中間出現pause,resume之後保持FinalTime時間不變

withMisfireHandlingInstructionNowWithRemainingCount
——以當前時間爲觸發頻率當即觸發執行
——執行至FinalTIme的剩餘週期次數
——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
——此指令致使trigger忘記原始設置的starttime和repeat-count
——觸發器的repeat-count將被設置爲剩餘的次數
——這樣會致使後面沒法得到原始設定的starttime和repeat-count值

cronTrigger

使用場景:CronTrigger比SimpleTrigger更經常使用,當你須要一個基於日曆般概念的做業調度器,而不是像SimpleTrigger那樣精確指定間隔時間。

使用cronTrigger,你能夠這樣指定觸發時間表例如每週五的中午,或是每週末的上午9:30,甚至是一月份每週1、3、五上午9:00到10:00之間每5分鐘

CronTrigger也須要指定startTime讓調度器生效,指定endTime讓調度器終止。

cron表達式

Cron表達式其實是由7個子表達式組成的字符串,這些子表達式用空格隔開,分別表明:

類型 範圍
0-60
0-60
小時 0-23
月份中的天數 0-31,但須要注意,有些月份如沒有31
0-11,可使用:JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC
星期中的天數 1-7,可使用: SUN,MON,TUE,WED,THU,FRI,SAT
年(可選) 通常不用

符號介紹:

/ : - 若是你在分鐘字段寫「0/15」,這表示「每次從一小時中的第0分鐘開始,每隔15分鐘觸發」, - 若是你在分鐘字段上寫「3/20」,這表示「每次從一小時中的第3分鐘開始,每隔20分鐘觸發」——換句話說,這跟在分鐘字段上指定「3,23,43」是同樣的。

? : - 字符容許出如今月份中的天數和星期中的天數字段中。它通常用來指定「不關心的值」。 - 當你須要在這兩個字段中的一個指定不肯定的值是很是方便的,這個字符不能用在其餘的字段中。

L : - 字符容許出如今月份中的天數和星期中的天數字段中 - 「L」字符出如今月份中的天數字段中表示「每個月的最後一天」——1月31日,平年的2月28日

w : - 字符用來指定給定日期的最近一個工做日(工做日指的是從週一到週五) - 若是你在月份中的天數字段的值指定爲「15w」,這表示「離每個月15號最近的工做日」。

'井' : - 」字符用來指定每個月的第N個工做日 - 星期中的天數字段的值爲「6#3」或是「FRI#3」表示「每個月的第三個星期五」。

經常使用表達式案例

Cron案例1——僅僅表示每隔5分鐘觸發一次:"0 0/5 * * * ?"

Cron案例2——表示每隔5分鐘,在過了10秒後觸發一次(例如上午10:00:10,10:05:10等):"10 0/5 * * * ?"

Cron案例3——表示每一個週三到週五,在上午10:30,11:30,12:30和13:30分觸發:"0 30 10-13 ? * WED,FRI"

Cron案例4——表示每個月從5號到20號,上午8時到10時之間的每半小時觸發,注意這個觸發器只在8:00,8:30,9:00和9:30分觸發,上午10:00不會觸發:"0 0/30 8-9 5,20 * ?"

注意有些調度需求因太複雜例如「上午9:00到10:00之間的每5分鐘,下午1:00到10:00的每20分鐘」,而不能用單一的觸發器來表示。這種狀況的解決方案是建立兩個簡單的觸發器,將它們註冊到調度器中去運行同一個做業任務。

代碼實現(CronTrigger構建)

觸發器,天天從的下午3:33 觸發一次

private static CronTrigger getTrigger5() throws ParseException {
        //定義一個任務觸發器
        return newTrigger()
                .withIdentity("job1", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0 27 16  * * ?"))
                //或者下邊這樣寫
                // .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(15, 33))
                .forJob("job1", "group1")
                .build();
    }

注:CronScheduleBuilder默認提供了一些經常使用表達式實現,以下圖,請自行嘗試

<img src="https://ws2.sinaimg.cn/mw690/005AQjvJly1fw440fu2jnj31dw0fowkp.jpg" alt="image">

觸發失敗指令(待完善。。。)

CronTrigger的觸發失敗指令常量:

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY  
MISFIRE_INSTRUCTION_DO_NOTHING  
MISFIRE_INSTRUCTION_FIRE_NOW

觸發指令設置:

withMisfireHandlingInstructionDoNothing
——不觸發當即執行
——等待下次Cron觸發頻率到達時刻開始按照Cron頻率依次執行

withMisfireHandlingInstructionIgnoreMisfires
——以錯過的第一個頻率時間馬上開始執行
——重作錯過的全部頻率週期後
——當下一次觸發頻率發生時間大於當前時間後,再按照正常的Cron頻率依次執行

withMisfireHandlingInstructionFireAndProceed
——以當前時間爲觸發頻率馬上觸發一次執行
——而後按照Cron頻率依次執行

暫停及恢復補全問題

問題介紹: - 1).執行暫停任務,重啓後,在暫停期間沒執行的任務又TM給補上了 - 2).服務器掛了,重啓後,在暫停期間沒執行的任務又TM給補上了

解決方式:

  • 1).先設置觸發失敗指令
cronSchedule(cronExpression).withMisfireHandlingInstructionFireAndProceed()
   或者
   cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing()

設置完成從新啓動發現沒軟用

  • 2).配置參數 quartz.properties中
#這個時間大於10000(10秒)會致使MISFIRE_INSTRUCTION_DO_NOTHING不起做用。
org.quartz.jobStore.misfireThreshold = 5000

解釋:

misfireThreshold表示實際執行的時間與下一次應該執行時間之間的差值,超過這個差值就不會執行,低於這個差值就會執行。 好比我每3秒執行一次,misfireThreshold=6000,當你暫停低於6秒內,它會彌補執行,超過6秒,它就再也不彌補執行了。

參見:

(quartz暫停及恢復任務解決恢復時一咕嚕把未執行的全補回來的問題)[http://www.itboth.com/d/mqE3In/quartz-java]<br> (quartz 失敗觸發指令)[http://www.voidcn.com/article/p-yvvrqdrt-ku.html]<br>

相關文章
相關標籤/搜索