spring中的任務調度Quartz


Spring 整合 Quartz 任務調度

  主要有兩種方式。

  Quartz的官網:http://www.quartz-scheduler.org/

  這兩種只是一些配置文件簡單配置就OK了,但是根本無法明白其中的內涵所在,在上一篇的   quartz 不同時間間隔調度任務  有所介紹,可以仔細參考

  話不多說直接上方案

  第一種:xml配置形式


 

  第一步

  以Maven形式添加依賴

   <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz</artifactId>
      <version>2.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz-jobs</artifactId>
      <version>2.2.3</version>
    </dependency>

  第二步

  配置xml   spring-quartz.xml  

  你需要將這個配置<import resource="spring-quartz.xml"></import>到你的spring中

  這其中也沒啥

  創建 MethodInvokingJobDetailFactoryBean  基本屬性的配置 需要執行的任務類方法

  創建 CronTriggerFactoryBean                       主要是觸發任務的,配置任務觸發的時間,可以又多個觸發器

  創建 SchedulerFactoryBean       調度工廠的作用,大家都把任務放入其中,在其中執行

<?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"
       default-autowire="byType">
    <!-- ======================== 任務 Task配置 ======================== -->
    <!--由MethodInvokingJobDetailFactoryBean實現-->
    <bean id="WxPayBillTask" class="com.jlnku.task.WxPayBillTask"></bean>
    <bean id="importOneJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="WxPayBillTask" />          <!--//執行類的實例-->
        <property name="targetMethod" value="run" />                   <!--//執行方法-->
        <property name="concurrent" value="false" />
        <property name="arguments">
            <list></list>
        </property>
    </bean>

    <!-- ======================== 配置定時調度 觸發器 ======================== -->
    <!--由CronTriggerFactoryBean實現-->
    <bean id="cronTrigger2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="importOneJob" />                <!-- //上面任務的Task配置bean-->
        <property name="cronExpression" value="0 02 17 ? * *"  />         <!--//觸發時機表達式  cron表達式在文章的最末尾會說-->
    </bean>
    <!-- ======================== 調度工廠(中心調度器) ======================== -->
    <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
          autowire="no">
        <property name="triggers">
            <list>
                <ref bean="cronTrigger2" />                           <!--//上面配置的觸發器-->
            </list>
        </property>
    </bean>
</beans>

  第三步

  創建你的任務,以線程的形式

  其中寫你的需要調度的任務邏輯,根據需求編寫再次 方法中就ok

/**
 * @author zhouguanglin
 * @date 2018/7/5 15:08
 */
@Component("WxPayBillTask")
public class WxPayBillTask implements Runnable{
    @Autowired
    WXPayService wxPayService;
    @Override
    public void run() {
        try {
            SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.DATE, -6);
            String date = df.format(calendar.getTime());
            wxPayService.insertWxDownloadBill(null, null, date);
        } catch (Exception e) {

        }
    }
}

  第二種:注解形式


 

  第一步

  加入依賴

   <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
    </dependency>

  第二步

  在Spring配置開啟task任務注解 ,注意你的類也是需要被掃描到的

<!-- task -->
<task:annotation-driven />

  第三步

  自己隨便創建一個任務調度的類,內部寫和調用自己的邏輯

  

@Component
public class JobDemo {
    @Autowired
    WXPayService wxPayService;
    @Scheduled(cron = "5 * * * * ?")
    public void FaceBookMessage() {
        System.out.println("----------------------------任務調度器---------------------------");
    }


    @Scheduled(cron = "0 43 17 ? * *")
    public void wxPayBillTask(){
        try {
            SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.DATE, -1);
            String date = df.format(calendar.getTime());
            wxPayService.insertWxDownloadBill(null, null, date);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  這樣就完事了


 

Trigger


 

在開始詳解每一種Trigger之前,需要先了解一下Trigger的一些共性。

StartTime & EndTime

startTime和endTime指定的Trigger會被觸發的時間區間。在這個區間之外,Trigger是不會被觸發的。

** 所有Trigger都會包含這兩個屬性 **

優先級(Priority)

當scheduler比較繁忙的時候,可能在同一個時刻,有多個Trigger被觸發了,但資源不足(比如線程池不足)。那么這個時候比剪刀石頭布更好的方式,就是設置優先級。優先級高的先執行。

需要注意的是,優先級只有在同一時刻執行的Trigger之間才會起作用,如果一個Trigger是9:00,另一個Trigger是9:30。那么無論后一個優先級多高,前一個都是先執行。

優先級的值默認是5,當為負數時使用默認值。最大值似乎沒有指定,但建議遵循Java的標准,使用1-10,不然鬼才知道看到【優先級為10】是時,上頭還有沒有更大的值。

Misfire(錯失觸發)策略

類似的Scheduler資源不足的時候,或者機器崩潰重啟等,有可能某一些Trigger在應該觸發的時間點沒有被觸發,也就是Miss Fire了。這個時候Trigger需要一個策略來處理這種情況。每種Trigger可選的策略各不相同。

這里有兩個點需要重點注意:

  • MisFire的觸發是有一個閥值,這個閥值是配置在JobStore的。比RAMJobStore是org.quartz.jobStore.misfireThreshold。只有超過這個閥值,才會算MisFire。小於這個閥值,Quartz是會全部重新觸發。

所有MisFire的策略實際上都是解答兩個問題:

  1. 已經MisFire的任務還要重新觸發嗎?
  2. 如果發生MisFire,要調整現有的調度時間嗎?

比如SimpleTrigger的MisFire策略有:

  • MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY

    這個不是忽略已經錯失的觸發的意思,而是說忽略MisFire策略。它會在資源合適的時候,重新觸發所有的MisFire任務,並且不會影響現有的調度時間。

    比如,SimpleTrigger每15秒執行一次,而中間有5分鍾時間它都MisFire了,一共錯失了20個,5分鍾后,假設資源充足了,並且任務允許並發,它會被一次性觸發。

    這個屬性是所有Trigger都適用。

  • MISFIRE_INSTRUCTION_FIRE_NOW

    忽略已經MisFire的任務,並且立即執行調度。這通常只適用於只執行一次的任務。

  • MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT

    將startTime設置當前時間,立即重新調度任務,包括的MisFire的

  • MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT

    類似MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT,區別在於會忽略已經MisFire的任務

  • MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

    在下一次調度時間點,重新開始調度任務,包括的MisFire的

  • MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT

    類似於MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT,區別在於會忽略已經MisFire的任務。

  • MISFIRE_INSTRUCTION_SMART_POLICY

    所有的Trigger的MisFire默認值都是這個,大致意思是“把處理邏輯交給聰明的Quartz去決定”。基本策略是,

    1. 如果是只執行一次的調度,使用MISFIRE_INSTRUCTION_FIRE_NOW
    2. 如果是無限次的調度(repeatCount是無限的),使用MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
    3. 否則,使用MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT  

Cron表達式

位置 時間域 允許值 特殊值
1 0-59 , - * /
2 分鍾 0-59 , - * /
3 小時 0-23 , - * /
4 日期 1-31 , - * ? / L W C
5 月份 1-12 , - * /
6 星期 1-7 , - * ? / L C #
7 年份(可選) 1-31 , - * /

星號():可用在所有字段中,表示對應時間域的每一個時刻,例如, 在分鍾字段時,表示“每分鍾”;

問號(?):該字符只在日期和星期字段中使用,它通常指定為“無意義的值”,相當於點位符;

減號(-):表達一個范圍,如在小時字段中使用“10-12”,則表示從10到12點,即10,11,12;

逗號(,):表達一個列表值,如在星期字段中使用“MON,WED,FRI”,則表示星期一,星期三和星期五;

斜杠(/):x/y表達一個等步長序列,x為起始值,y為增量步長值。如在分鍾字段中使用0/15,則表示為0,15,30和45秒,而5/15在分鍾字段中表示5,20,35,50,你也可以使用*/y,它等同於0/y;

L:該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個字段中意思不同。L在日期字段中,表示這個月份的最后一天,如一月的31號,非閏年二月的28號;如果L用在星期中,則表示星期六,等同於7。但是,如果L出現在星期字段里,而且在前面有一個數值X,則表示“這個月的最后X天”,例如,6L表示該月的最后星期五;

W:該字符只能出現在日期字段里,是對前導日期的修飾,表示離該日期最近的工作日。例如15W表示離該月15號最近的工作日,如果該月15號是星期六,則匹配14號星期五;如果15日是星期日,則匹配16號星期一;如果15號是星期二,那結果就是15號星期二。但必須注意關聯的匹配日期不能夠跨月,如你指定1W,如果1號是星期六,結果匹配的是3號星期一,而非上個月最后的那天。W字符串只能指定單一日期,而不能指定日期范圍;

LW組合:在日期字段可以組合使用LW,它的意思是當月的最后一個工作日;

井號(#):該字符只能在星期字段中使用,表示當月某個工作日。如6#3表示當月的第三個星期五(6表示星期五,#3表示當前的第三個),而4#5表示當月的第五個星期三,假設當月沒有第五個星期三,忽略不觸發;

C:該字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是計划所關聯的日期,如果日期沒有被關聯,則相當於日歷中所有日期。例如5C在日期字段中就相當於日歷5日以后的第一天。1C在星期字段中相當於星期日后的第一天。

Cron表達式對特殊字符的大小寫不敏感,對代表星期的縮寫英文大小寫也不敏感。

一些例子:

 

表示式 說明
0 0 12 * * ? 每天12點運行
0 15 10 ? * * 每天10:15運行
0 15 10 * * ? 每天10:15運行
0 15 10 * * ? * 每天10:15運行
0 15 10 * * ? 2008 在2008年的每天10:15運行
0 * 14 * * ? 每天14點到15點之間每分鍾運行一次,開始於14:00,結束於14:59。
0 0/5 14 * * ? 每天14點到15點每5分鍾運行一次,開始於14:00,結束於14:55。
0 0/5 14,18 * * ? 每天14點到15點每5分鍾運行一次,此外每天18點到19點每5鍾也運行一次。
0 0-5 14 * * ? 每天14:00點到14:05,每分鍾運行一次。
0 10,44 14 ? 3 WED 3月每周三的14:10分到14: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 2007-2009 在2007,2008,2009年每個月的最后一個星期五的10:15分運行。
0 15 10 ? * 6#3 每月第三個星期五的10:15分運行。

   

 

 

              【版本聲明】本文為博主原創文章,轉載請注明出處


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM