1. 程式人生 > >定時任務知多少(一)——Spring實現記憶體級quartz

定時任務知多少(一)——Spring實現記憶體級quartz

開發需求中,我們經常會遇到定時處理的需求,比如說定時提醒使用者還款、定時備份資料庫、定時去合作公司檔案伺服器讀取資料、產品自動下架、使用者所下的訂單超時取消……等等等等,從本篇文章開始,我們來一起討論一下專案中定時任務的應用。

然而我們都知道:是先有業務,再有技術。技術是為業務而生的。所以對於不同的需求,我們需要使用不同的技術,來合理的解決需求的問題。總結一下,通過以下四個技術層面,能夠解決幾乎所有的定時需求:

1、Spring實現的記憶體級quartz;

2、JDK中Timer及JDK中其他定時處理類;

3、整合Spring,將quartz持久化到mongodb中;

4、quartz叢集。

……

今天,我們來講第一個,也是最簡單的一個。

一、Spring實現的記憶體級quartz

該定時任務,主要是Spring對quartz框架做的一個實現。它只需要進行簡單的配置,即可實現定時任務。配置如下:

<?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:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	 http://www.springframework.org/schema/tx
	 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	 http://www.springframework.org/schema/jee
	 http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
	 http://www.springframework.org/schema/aop
	 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	 http://www.springframework.org/schema/context
	 http://www.springframework.org/schema/context/spring-context-3.0.xsd
	 http://activemq.apache.org/schema/core
	 http://activemq.apache.org/schema/core/activemq-core.xsd"
	default-lazy-init="true">
	
	<!--注入一個bean  -->
	<bean id="testQtz"  class="com.quartz.TestQtz" />
	
	<!--指定定時執行的方法  -->
	<bean id="testQtzJobMethod"
		class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject">
			<ref bean="testQtz" />
		</property>
		<property name="targetMethod">
			<value>executeQtz</value> <!--指定testQtz Bean中,定時執行的方法名稱  -->
		</property>
	</bean>

	<!-- ======================== 排程觸發器 ======================== -->
	<!-- 設定幾點開始週期性 的 執行 -->
	<bean id="testQtzCronTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
   		<property name="jobDetail" ref="testQtzJobMethod" />
		<property name="cronExpression" value="0 01 0 * * ?" />   <!-- 工作日的 00:01分執行 -->
	</bean>
	
	
	<!-- ======================== 排程工廠 ======================== -->
	
	<!-- 排程工廠 -->
	<bean id="SpringJobSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="triggers">
		     <list>
			     <ref local="testQtzCronTrigger" />
		    </list> 
		</property>
	</bean>
	
</beans>


定時任務將執行的方法類如下:

package com.quartz.testQtz;

public class TestQtz {

	private static int counter = 0;  
    public void executeQtz()  {  
        counter++;  
        System.out.println("第 " + counter +" 次執行");  
    }  
}


這樣就可以了,上面的配置加方法,就可以執行定時任務了,很簡單吧。

下面我們來大概說一下它的原理。

上面的這種定時任務的實現,還是非常普遍的,因為使用起來非常的簡單,只需要一個Spring的簡單的配置,即可完成需求。實際上,這是Spring做的一個對Quartz的一個比較完整的實現,所以我們用來起來才沒有感覺到Quartz的存在,所以才會覺得很簡單。

我們通過上面Spring的配置,通過設定cronExpression,我們可以使要執行的方法週期性的執行。比如每天晚上12點鐘,準時備份資料庫,比如還差3天使用者將逾期時,傳送提醒簡訊等等。我們都可以使用該種方式執行。

尺有所長,寸有所短。儘管上述方法用起來很方便,但是我能夠容納它的缺點,才能夠對症下藥。

缺點如下:

1、該種方法,是將定時任務序列化到記憶體當中的。也就是說,當系統重新部署,需要重啟伺服器時,該定時任務會從記憶體中清除(幾乎是廢話,應用伺服器都停了,定時任務還怎麼能夠在記憶體當中。。),當應用伺服器重新啟動後,定時任務才會重新載入記憶體當中。

所以說,這種定時任務,應用伺服器停止時間如果比較長的話,則當日此期間未執行的定時任務,就沒有機會執行了。

2、執行執行並不是非常準確的(即執行時間不準確)。也就是說定點兒執行的定時任務,到了時間可能仍然沒有執行。這是為什麼呢?定時任務,說白了,就是一個程序。應用伺服器啟動時,定時任務進入記憶體,並進入阻塞狀態。這時,我們可以理解為有一個timer不斷去掃面執行時間。當到執行時間是,經過記憶體排程,即將執行的定時任務進入就緒狀態,等待CPU進行排程,注意它並不會阻塞其他執行緒的排程,而是將自己置於就緒狀態等待CPU空閒時排程。所以說,如果CPU一直忙碌的話,就會發生定時任務到時間仍未執行的情況。

綜合上述這兩種缺點,我們就清楚瞭如何、以及合適使用該種定時任務了。

實際應用中,由於這種定時任務的需求比較特殊,我們經常會將定時任務分離出來,將其作為一個獨立的專案,獨立部署。因為應用伺服器是需要更改的,不斷的產品迭代、產品的上線,很可能會重新啟動應用伺服器,為了不對定時任務造成影響,我們通常會將其分離出來對部署。

由於定時任務,並非準確執行,我們需要容忍它這一點(其實相差時間不會很大)。

本文只是簡單介紹了定時任務,非常簡單的一種實現,接下來我將會介紹quartz強大的功能,敬請期待。