Spring提供的三種定時任務機制及其比較

 定時任務的需求在衆多應用系統中普遍存在,在Spring中,咱們能夠使用三種不一樣的定時機制,下面一一描述並加以比較html

1. 基於Quartz的定時機制

 Spring基於Quartz的定時機制

下面詳細解釋這個類圖中涉及的關鍵類及其使用場景java

1.1. SchedulerFactoryBean

這是Spring中基於Quartz的定時機制入口,只要Spring容器裝載了這個類,Quartz定時機制就會啓動,並加載定義在這個類中的全部triggerlinux

 

Spring配置範例:程序員

 

 

1.2. CronTriggerBean

實現了Trigger接口,基於Cron表達式的觸發器spring

 

這種觸發器的好處是表達式與linux下的crontab一致,可以知足很是複雜的定時需求,也容易配置express

 

Spring配置範例:服務器

 

 

1.3. SimpleTriggerBean

該類也實現了Trigger接口,基於配置的定時調度併發

 

這個觸發器的優勢在於很容易配置一個簡單的定時調度策略app

 

Spring配置範例:異步

 

 

 

1.4. JobDetailBean

JobDetail類的簡單擴展,可以包裝一個繼承自QuartzJobBean的普通Bean,使之成爲定時運行的Job

 

缺點是包裝的Bean必須繼承自一個指定的類,通用性不強,對普通Job的侵入性過強,不推薦使用

1.5. MethodInvokingJobDetailFactoryBean

Spring提供的一個不錯的JobDetail包裝工具,可以包裝任何bean,並執行類中指定的任何stati或非static的方法,避免強制要求bean去實現某接口或繼承某基礎類

 

Spring配置範例:

 

 

 

 

1.6. 關於TriggerListener和JobListener

Quartz中提供了相似WebWork的攔截器的功能,系統執行任務前或任務執行完畢後,都會檢查是否有對應的Listener須要被執行,這種AOP的思想爲咱們帶來了靈活的業務需求實現方式。

 

例如如今有一個簡單的業務要求:任務執行前先判斷當前服務器是否爲task服務器,不是則不執行任務。對於這種業務需求,咱們能夠簡單的實現一個TriggerListener,並將其插入SchedulerFactoryBean的globalTriggerListeners中,這樣全部的job在執行先後都會調用TriggerListener中對應的方法。

 

代碼範例:

 

[java]  view plain copy
  1. public class MyTaskTriggerListener implements TriggerListener {  
  2.     protected static final Log logger = LogFactory.getLog(MyTaskTriggerListener.class);  
  3.   
  4.     /** 
  5.      * 須要運行task任務的機器列表 
  6.      */  
  7.     private String taskServers;  
  8.   
  9.     public String getName() {  
  10.         return "MyTaskTriggerListener";  
  11.     }  
  12.   
  13.     public void triggerComplete(Trigger arg0, JobExecutionContext arg1, int arg2) {  
  14.     }  
  15.   
  16.     public void triggerFired(Trigger arg0, JobExecutionContext arg1) {  
  17.     }  
  18.   
  19.     public void triggerMisfired(Trigger arg0) {  
  20.     }  
  21.   
  22.     /** 
  23.      * 判斷當前服務器是否爲task服務器,來決定是否執行task 
  24.      * @return 
  25.      */  
  26.     public boolean vetoJobExecution(Trigger arg0, JobExecutionContext arg1) {  
  27.         String serverName;  
  28.         try {  
  29.             serverName = InetAddress.getLocalHost().getHostName();//獲取主機名  
  30.         } catch (UnknownHostException e) {  
  31.             e.printStackTrace();  
  32.             return true;  
  33.         }  
  34.         if (taskServers.indexOf(serverName) > -1) {  
  35.             if (logger.isInfoEnabled()) {  
  36.                 logger.info("this is a task server, job will be executed");  
  37.             }  
  38.             return false;  
  39.         } else {  
  40.             if (logger.isInfoEnabled()) {  
  41.                 logger.info("this is not a task server, job will be vetoed");  
  42.             }  
  43.             return true;  
  44.         }  
  45.     }  
  46.   
  47.     public String getTaskServers() {  
  48.         return taskServers;  
  49.     }  
  50.   
  51.     public void setTaskServers(String taskServers) {  
  52.         this.taskServers = taskServers;  
  53.     }  
  54. }  

 

 

2. 基於Timer的定時機制

JDK提供了基礎的定時類:Timer,在這個類的基礎上,Spring提供了一套簡單的定時機制

Spring基於Timer的定時機制

下面詳細解釋這個類圖中涉及的關鍵類及其使用場景

 

2.1. TimerFactoryBean

這個類很是相似Quartz中的SchedulerFactoryBean,是基於Timer的定時機制的入口,Spring容器裝載此類後會自動開始定時器

 

Spring配置範例:

 

 

 

2.2. ScheduledTimerTask

相似於Quartz中的Trigger的SimpleTriggerBean實現,任務是在設定的時間觸發並執行配置的任務,特色是配置簡單、明瞭,使用於簡單的任務觸發邏輯

 

Spring配置範例:

 

 

 

2.3. TimerTask抽象類

普通task實現必需要繼承的父類,主要包含一個run()的方法,相似Quartz中的QuartzJobBean,對應用侵入性較強,也不推薦使用

2.4. MethodInvokingTimerTaskFactoryBean

相似Quartz中的MethodInvokingJobDetailFactoryBean,用於封裝任何bean,並能夠執行bean中的任意方法,再也不復述

 

3. 基於Executor的定時機制

Spring基於Executor的定時機制 

這種定時機制與上面兩種定時機制沒有太大區別,特別是在配置和實現功能上,不一樣的是它的核心是基於ScheduledExecutorService(ScheduledThreadPoolExecutor是默認實現),一種JDK5.0中提供的基於線程的併發機制,關於JDK5中的線程池的概念及其一些深刻分析,請參考老唐的博客:http://blog.csdn.net/sfdev/archive/2008/12/30/3648457.aspx 這裏再也不復述

 

4. 三種定時機制的比較和案例分析

看完了這三種定時機制,各有各的優劣,不一樣場景下咱們應該靈活選擇不一樣的定時機制。總的來講,若是咱們須要簡單的定時器,咱們能夠選用基於timer的定時器,若是定時規則較爲複雜,咱們能夠選用基於Quartz的定時器,若是咱們要用到線程池來處理異步任務,咱們能夠選用基於Executor的定時機制,雖然只是任務實現中用到線程池,畢竟也是一脈相承的,固然也能夠用Quartz的定時器+基於Executor的任務線程池,徹底沒有任何衝突的。

 

說這麼多,仍是比較抽象,不如咱們來分析一下老唐的Notify系統來加深對Spring定時機制的瞭解(詳細設計參考最近一期的程序員雜誌)。

 

在老唐的Notify系統中,徹底使用了基於JDK5.0中的Executor的定時機制,即由一個ScheduledExecutorFactoryBean觸發系統的每隔2分鐘運行一個單線程的任務,在這個任務中,執行完各類機制檢查和配置策略後,將要執行的Notify任務放入一個已配置好的線程池,並由線程池指定線程來完成Notify的任務。

在最近一期的項目中,咱們將task移植到了apps,Notify系統也同時被移植過來了,爲了統一全部的task,咱們將之前task中基於timer、Quartz和Executor的各類任務統一改成基於Quartz的調度。在這個過程當中,Notify系統的基於Executor的定時機制也被改成基於Quartz的定時機制,過程很是順利。基於此次移植項目,能夠說這三種定時機制是很是容易互換的,而且通用性比較強,只須要簡單的配置便可。

相關文章
相關標籤/搜索