1. 程式人生 > 程式設計 >Spring定時服務QuartZ原理及程式碼案例

Spring定時服務QuartZ原理及程式碼案例

  在JavaEE系統中,我們會經常用到定時任務,比如每天凌晨生成前天報表,每一小時生成彙總資料等等。

  我們可以使用java.util.Timer結合java.util.TimerTask來完成這項工作,但時排程控制非常不方便,並且我們需要大量的程式碼。

  使用Quartz框架無疑是非常好的選擇,並且與Spring可以非常方便的整合。

  Spring提供了支援時序排程的整合類。整個構建任務排程服務需要三步:

  1)向專案中新增jar包:新增quartz.jar包,將他加到你工程的classpath中去。

  2)寫Class檔案,在檔案中定義你要執行操作的函式你就可以通過配置來達到定時操作了。

  3)提供applicationContext.xml Spring配置檔案,其中配置你的定時傳送操作以及設定定時器的各種屬性(包括執行頻率和初始執行時機)。 

  小編做了一個每5秒列印一次當前時間的例子,具體請參考原始碼,尤其注意配置檔案的寫法。(詳見下面“示例”)

什麼是Quartz?

  Quartz是一個強大的企業級任務排程框架。它允許開發人員靈活地定義觸發器的排程時間表,並可對觸發器和任務進行關聯對映。此外,Quartz提供了排程執行環境的持久化機制,可以儲存並會發排程現場,即使系統因故障關閉,任務排程現場資料並不會丟失。Spring中繼承並簡化了Quartz。

如何使用Quartz?


  對於Quartz,我們使用的時候主要是注重兩個方面,一個是定時任務的業務,另一個就是Cron表示式。

  1>Quartz存在兩種方式來定義定時執行任務,一種是使用QuartJobBean和JobDetailBean;另一種是使用MethodInvokingJobDetailFactoryBean。

  2>Cron表示式包括下面7個欄位並區別順序:秒0-59,分0-59,小時0-23,月內日期1-31,月1-12或者JAN-DEC,周內日期1-7或者SUN-SAT,年(可選欄位)留空或者1970-2099並且通過特殊字元表示特殊意義,具體為下:

  • 斜線(/)字元表示增量值。例如,在秒欄位中"5/15"代表從第5秒開始,每15秒一次。
  • 問號(?)字元和字母L字元只有在月內日期和周內日期欄位中可用。問號表示這個欄位不包含具體值。所以,如果指定月內日期,可以在周內日期欄位中插入"?",表示周內日期值無關緊要。這裡有個很蛋疼的設定,無關Quartz,而是Spring整合Quartz後,它自己加的一個約束,那就是:日期(1-31)和星期(SUN-SAT)兩者,必須有一個是問號(?),系統在啟動的時候,Spring會檢查表示式,如果不符合它的規則,就會拋異常。所以在使用的時候這個地方一定要注意,而這個在Linux上執行Cron是沒有這個限制的。
  • 字母L字元是last的縮寫。放在月內日期欄位中,表示安排在當月最後一天執行。在周內日期欄位中,如果"L"單獨存在,就等於"7",否則代表當月內周內日期的最後一個例項。所以"0L"表示安排在當月的最後一個星期日執行。
  • 字母(W)字元把執行安排在最靠近指定值的工作日。把"1W"放在月內日期欄位中,表示把執行安排在當月的第一個工作日內。
  • 井號(#)字元為給定月份指定具體的工作日例項。把"MON#2"放在周內日期欄位中,表示把任務安排在當月的第二個星期一。
  • 星號(*)字元是通配字元,表示該欄位可以接受任何可能的值、表示式例子。

例子:

      "0 0 08 * * ?" 每天上午8點觸發
      "0 15 10 ? * *" 每天上午10:15觸發
      "0 15 10 * * ?" 每天上午10:15觸發
      "0 15 10 ? * 6L 2009-2019" 2009年至2019年的每月的最後一個星期五上午10:15觸發
      "0 15 10 ? * 6#3" 每月的第三個星期五上午10:15觸發

【示例】

  我們使用Spring定時服務Quartz來實現一個每5秒列印一次當前時間的小例子。

  1:定義介面IPrintInfoService類

package demoinfo.spring.quartz;
public interface IPrintInfoService {
  public void print();
}

  2:實現介面類PrintInfoServiceImpl

package demoinfo.spring.quartz;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import demoinfo.spring.quartz.IPrintInfoService;

public class PrintInfoServiceImpl implements IPrintInfoService{

  public void print() {
    Calendar now = Calendar.getInstance();
    System.out.println("現在是北京時間:" + this.format(now.getTime()));
  }

  public String format(Date date){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sdf.format(date);
  }

}

  3:基於QuartzJobBean的實現類PrintInfoJob

package demoinfo.spring.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import demoinfo.spring.quartz.IPrintInfoService;

public class PrintInfoJob extends QuartzJobBean{
  
  private IPrintInfoService prinfInfoService = null;
  public IPrintInfoService getPrinfInfoService() {
    return prinfInfoService;
  }
  public void setPrinfInfoService(IPrintInfoService prinfInfoService) {
    this.prinfInfoService = prinfInfoService;
  }
  @Override
  protected void executeInternal(JobExecutionContext arg0)
      throws JobExecutionException {
    this.prinfInfoService.print();
  }
}

  4:Spring配置檔案applicationContext.xml

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


  <bean id="printInfoService" class="demoinfo.spring.quartz.PrintInfoServiceImpl" />
  <!-- 配置一個Job -->
  <bean id="printInfoJob" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="demoinfo.spring.quartz.PrintInfoJob" />
    <property name="jobDataAsMap">
      <map>
        <entry key="prinfInfoService" value-ref="printInfoService"></entry>
      </map>
    </property>
  </bean>

  <!-- 簡單的觸發器 -->
  <bean id="simplePrintInfoTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
    <property name="jobDetail">
      <ref bean="printInfoJob" />
    </property>
    <property name="startDelay">
      <value>6000</value>
    </property>
    <property name="repeatInterval">
      <value>6000</value>
    </property>
  </bean>

  <!--複雜的觸發器 -->
  <bean id="complexPrintInfoTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail">
      <ref bean="printInfoJob" />
    </property>
    <property name="cronExpression">
      <value>00,05,10,15,20,25,30,35,40,45,50,55 * * * * ?</value>
    </property>
  </bean>

  <!-- spring觸發工廠 -->
  <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
      <list>
        <ref bean="complexPrintInfoTrigger" />
      </list>
    </property>
  </bean>
</beans>

  5:測試用例類SpringQuartzDemo

package demoinfo.spring.quartz;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringQuartzDemo {

  public static void main(String[] args) {
    System.out.println("測試開始......");
    new ClassPathXmlApplicationContext(
        "classpath:demoinfo/spring/quartz/applicationContext.xml");
    System.out.println("測試結束......");
  }

}

  執行測試用例,可以看到控制檯每過5秒鐘就列印一次時間資訊。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。