spring定時服務講解

1 前言


         本文檔是描述Spring服務開發過程,用於開發人員培訓和交流,有不足之處還望諒解和指出。 java


Spring定時服務


2.1 介紹

Spring定時服務包括 Spring自帶定時服務和集成 Quartz定時服務框架兩類。


Spring定時服務依賴於jar包是Spring.jar,這個包不用多說了,是Spring Framework必備的一個包。 spring


Spring自帶定時服務


Spring自帶定時服務

一、必須繼承java.util.TimerTaskJaveBean。 數據庫

二、註冊到Spring框架提供的任務調度org.springframework.scheduling.timer.ScheduledTimerTask當中。 服務器

3.1 開發過程


3.1.1 繼承TimerTask

package test.timerTask;
 
 import java.util.TimerTask;
 
 public class Task extends TimerTask {

   public void run() {
     // TODO Auto-generated method stub
    System.out.println("測試TimerTask : Hello !!");
  }

}

3.1.2 註冊Spring任務調度


<bean id="sayHelloTask" class="test.springTimer.Task"></bean>
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask">
<ref bean="sayHelloTask"/>
</property>
<!-- 任務執行週期 2m 關於一些任務的參數請參考JDK doc文檔和Spring相關文檔-->
<property name="period">
<value>2000</value>
</property>
<!-- 延時1m 執行任務 -->
<property name="delay">
<value>1000</value>
</property>
</bean>

4 集成Quartz定時服務框架


Quartz是徹底由 Jave 開發的開源做業調度框架,提供的功能十分強大,而且靈活,蔽了底層複雜的任務調度和策略處理過程,讓開發人員集中精力聚焦在業務問題和業務實現上。

Quartz優勢是: 負載均衡

一、能嵌入到任何獨立的應用中運行。 框架

二、能在應用服務器或者Servlet 容器中實例化,而且可以參與XA事務。 ide

三、可以以獨立的方式運行(在它本身的Java 虛擬機中),能夠經過RMI 使用Quartz 性能

四、能夠被實例化爲獨立程序的集羣(有負載均衡和容錯能力)。 測試



4.1 Quartz觸發器


4.1.1 SimpleTrigger

若是須要讓任務只在某個時刻執行一次,或者,在某個時刻開始,而後按照某個時間間隔重複執行,簡單地說,若是你想讓觸發器在 2005 1 13日,上午 112354秒執行,而後每一個隔10秒鐘重複執行一次,而且這樣重複5 次。那麼SimpleTrigger就能夠知足你的要求。 spa


4.1.2 CronTrigger

若是你須要像日曆那樣按日程來觸發任務,而不是像SimpleTrigger 那樣每隔特定的間隔時間觸發,CronTriggers 一般比SimpleTrigger更有用。 

使用CronTrigger ,你能夠指定諸如「每一個週五中午」,或者「每一個工做日的 9:30」或者「從每一個周1、周3、週五的上午 900到上午1000之間每隔五分鐘」這樣日程安排來觸發。甚至,象SimpleTrigger同樣,CronTrigger 也有一個startTime以指定日程從何時開始,也有一個(可選的)endTime 以指定什麼時候日程再也不繼續。

Cron Expressions——Cron表達式

Cron表達式被用來配置CronTrigger 實例。Cron表達式是一個由7 個子表達式組成的字符串。每一個子表達式都描述了一個單獨的日程細節。這些子表達式用空格分隔,分別表示:

    1.   Seconds  秒 

    2.   Minutes 分鐘

    3.   Hours 小時

    4.   Day-of-Month 月中的天 

    5.   Month 月

    6.   Day-of-Week  週中的天 

    7.   Year (optional field) 年(可選的域)


一個cron表達式的例子字符串爲"0 0 12 ? * WED", 這表示「每週三的中午1200」。單個子表達式能夠包含範圍或者列表。例如:前面例子中的週中的天這個域(這裏是"WED")能夠被替換爲"MON-FRI", "MON, WED, FRI" 或者甚至"MON-WED,SAT"

 通配符('*')能夠被用來表示域中「每一個」可能的值。所以在"Month"域中的*表示每月,而在Day-Of-Week 域中的*則表示「週中的每一天」。

全部的域中的值都有特定的合法範圍,這些值的合法範圍至關明顯,例如:秒和分域的合法值爲0 59,小時的合法範圍是 0 23Day-of-Month 中值得合法凡範圍是 031,可是須要注意不一樣的月份中的天數不一樣。月份的合法值是 0 11。或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV DEC來表示。Days-of-Week能夠用1 7 來表示(1=星期日)或者用字符串SUN, MON, TUE, WED,THU, FRI  和SAT 來表示.

'/' 字符用來表示值的增量,例如若是分鐘域中放入'0/15' ,它表示「每隔 15分鐘,從0 開始」,若是在份中域中使用'3/20' ,則表示「小時中每隔20分鐘,從第3 分鐘開始」或者另外相同的形式就是'3,23,43'

 '?'字符能夠用在 day-of-month day-of-week域中,它用來表示「沒有指定值」。這對於須要指定一個或者兩個域的值而不須要對其餘域進行設置來講至關有用。看下面例子(以及CronTrigger   JavaDOC )會更清楚。

 'L'字符能夠在day-of-month day-of-week中使用,這個字符是"last" 的簡寫,可是在兩個域中的意義不一樣。例如,在day-of-month 域中的"L" 表示這個月的最後一天,即,一月的31日,非閏年的二月的28日。若是它用在day-of-week中,則表示"7" 或者"SAT" 。可是若是在 day-of-week域中,這個字符跟在別的值後面,則表示" 當月的最後的周XXX"。例如:"6L"  或者 "FRIL" 都表示本月的最後一個週五。當使用'L'選項時,最重要的是不要指定列表或者值範圍,不然會致使混亂。

'W'  字符用來指定距離給定日最接近的周幾(在 day-of-week域中指定)。例如:若是你爲day-of-month 域指定爲"15W", 則表示「距離月中15號最近的周幾」。

'#' 表示表示月中的第幾個周幾。例如:day-of-week域中的"6#3"  或者 "FRI#3"表示「月中第三個週五」。

 下面是一些表達式以及它們的含義,你能夠在CronTrigger JavaDOC 中找大更多例子。



4.2 JobStores

JobStore 負責保持對全部scheduler 「工做數據」追蹤,這些工做數據包括:job(任務),trigger (觸發器),calendar(日曆) 等。

4.2.1 RAMJobStore

AMJobStore 是最簡單的JobStore,也是性能最好的(根據 CPU時間)。從名字就能夠直觀地看出,RAMJobStore 將全部的數據都保存在RAM中。這就是爲何它閃電般的快速和如此容易地配置。缺點就是當應用結束時全部的日程信息都會丟失,這意味着RAMJobStore 不能知足JobsTriggers的持久性(「non-volatility」)。對於有些應用來講,這是能夠接受的,甚至是指望的行爲。可是對於其餘應用來講,這將是災難。

爲了使用RAMJobStore(假設你使用StdSchedulerFactory),指使簡單地將類名org.quartz.simpl.RAMJobStore做爲你的quartz的配置值。



4.2.2 JDBCJobStore

數據經過JDBC 保存到數據庫可中, 配置要比RAMJobStore 稍微複雜,同時速度也沒有那麼快。DBCJobStore 幾乎能夠在任何數據庫上工做,它普遍地使用Oracle, MySQL, MS SQLServer2000, HSQLDB, PostreSQL  以及 DB2 。要使用JDBCJobStore ,首先必須建立一套Quartz使用的數據庫表,能夠在Quartz  docs/dbTables找到建立庫表SQL腳本。

    選擇事務的考慮:

    若是不想將scheduling命令綁到其餘的事務上,那麼你能夠經過對JobStore使用JobStoreTX來讓Quartz幫你管理事務(這是最廣泛的選擇)。

    若是想讓Quartz同其餘的事務協同工做(例如:J2EE應用服務器中的事務),那麼你須要用JobStoreCMT,這樣,Quartz就會讓應用服務器容器來管理事務。

4.3 Spring集成應用


4.3.1 繼承QuartzJobBean 

package test.timerTask;
 
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
 import org.springframework.scheduling.quartz.QuartzJobBean;
 
 public class SayHelloTaskUsingQuartz extends QuartzJobBean {
 
   @Override
  protected void executeInternal(JobExecutionContext context)
      throws JobExecutionException {
    // TODO Auto-generated method stub
    System.out.println("使用Quartz 認爲調度: Hello!!");
  }

}

4.3.2 註冊Spring

4.3.2.1 JobDetailBean

<bean id="sayHelloJob" class="org.springframework.scheduling.quartz.JobDetailBean">
 <property name="jobClass">
 <value>test.timerTask.SayHelloTaskUsingQuartz</value>
 </property>
 </bean> 

 <!-- 關鍵在以下兩個觸發器的配置 --> 

 <!-- 相似於Java的簡單觸發器 --> 
 
 <bean id="helloTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
 <property name="jobDetail">
 <ref bean="sayHelloJob"/>
 </property>
 <property name="startDelay">
 <value>1000</value>
 </property>
 <property name="repeatInterval">
 <value>3000</value>
 </property>
 </bean> 
     
 <!-- 複雜觸發器 --> 
 
 <bean id="helloCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
 <property name="jobDetail">
 <ref bean="sayHelloJob"/>
 </property>
 <property name="cronExpression"> 
   
 <!-- 關鍵在配置此表達式 --> 
 
 <value>0 49 15 * *  </value>
 </property>
 </bean>

4.3.2.2 MethodInvokingJobDetailFactoryBean

<bean id="methodInvokingJobDetail"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject"><ref bean="financeDAO"/></property>
        <property name="targetMethod"><value>confirmOrder</value></property>
    </bean>

    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail">
            <ref bean="methodInvokingJobDetail"/>
        </property>
        <property name="cronExpression">
            <value>0 0 6,12,20 * * ?</value>
        </property>
    </bean>

 <!-- 總管理類 若是將lazy-init='false'那麼容器啓動就會執行調度程序  -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list><ref local="cronTrigger"/></list>
        </property>
    <property name="quartzProperties">
    <props>
  		<prop key="org.quartz.threadPool.threadCount">1</prop>
  		<prop key="org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer">true</prop>
		<!--  
		<prop key="org.quartz.scheduler.instanceName">scheduler</prop>
		<prop key="org.quartz.scheduler.wrapJobExecutionInUserTransaction">true</prop>
		<prop key="org.quartz.scheduler.rmi.export">false</prop>
		<prop key="org.quartz.scheduler.rmi.proxy">false</prop>
		<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
		<prop key="org.quartz.threadPool.threadCount">5</prop>
		<prop key="org.quartz.threadPool.threadPriority">5</prop>
		<prop key="org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread">false</prop>
		<prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
		<prop key="org.quartz.jobStore.class">org.quartz.simpl.RAMJobStore</prop>
		-->
    </props>
 </bean>

本文中還沒有涉及到對spring定時服務進行集羣負載均衡配置,應用Quartz框架知識高級部分。

相關文章
相關標籤/搜索