https://www.jianshu.com/p/40490986fefejava
上次熟悉了MarkDown的用法以後,因爲各類緣由一直沒有時間更新博客。。。此次打算把我以前總結的一些東西陸陸續續的寫在博客裏,但願下次用到的時候可以快速記起來~spring
---------------------------------------華麗的分割線--------------------------------------------express
在應用開發中,常常須要一些週期性的操做,如:須要在天天凌晨時候分析一次前一天的日誌信息、須要每隔5分鐘檢查一下某個模塊是否有異常而後自動發送郵件給管理員,在項目運行到第30天的時候須要執行某些操做等等。這些功能需求就須要咱們使用一些定時任務方法去實現,本文將介紹目前J2EE項目經常使用的幾種定時任務方法並比較它們的優缺點。tomcat
2 J2EE項目中經常使用到的三種定時任務實現方法先來介紹下Java自帶的java.util.Timer類,這個類容許你調度一個java.util.TimerTask任務。使用這種方式可讓你的程序按照某一個頻度執行,但不能在指定時間運行。TimerTask類用於實現由Timer安排的一次或重複執行的某個任務。每個Timer對象對應的是一個線程,所以計時器所執行的任務應該迅速完成,不然會延遲後續的任務執行。併發
java.util.Timer類方法摘要app
void cancel() 終止此計時器,丟棄全部當前已安排的任務。 int purge() 今後計時器的任務隊列中移除全部已取消的任務。 void schedule(TimerTask task, Date time) 安排在指定的時間執行指定的任務。 void schedule(TimerTask task, Date firstTime, long period) 安排指定的任務在指定的時間開始進行重複的固定延遲執行。 void schedule(TimerTask task, long delay) 安排在指定延遲後執行指定的任務。 void schedule(TimerTask task, long delay, long period) 安排指定的任務從指定的延遲後開始進行重複的固定延遲執行。 void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 安排指定的任務在指定的時間開始進行重複的固定速率執行。 void scheduleAtFixedRate(TimerTask task, long delay, long period) 安排指定的任務在指定的延遲後開始進行重複的固定速率執行。框架
TimerTask類方法摘要ide
boolean cancel() 取消此計時器任務。 abstract void run() 此計時器任務要執行的操做。 long scheduledExecutionTime() 返回此任務最近實際執行的安排執行時間。工具
使用Timer類的schedule(TimerTask task, long delay, long period)方法啓動定時器。測試
Timer timer=new Timer(); MyTask myTask=new MyTask(); timer.schedule(myTask, 1000, 2000);
Timer timer=new Timer(); MyTask myTask=new MyTask(); timer.schedule(myTask, 1000, 2000);
TimerTask類主要實現run()方法裏的業務邏輯,用法以下:
import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimerTask; public class MyTask extends TimerTask { @Override public void run() { // TODO Auto-generated method stub SimpleDateFormat simpleDateFormat=null; simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); System.out.println("當前的系統時間爲:"+simpleDateFormat.format(new Date())); } }
import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimerTask; public class MyTask extends TimerTask { @Override public void run() { // TODO Auto-generated method stub SimpleDateFormat simpleDateFormat=null; simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"); System.out.println("當前的系統時間爲:"+simpleDateFormat.format(new Date())); } }
import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimerTask; public class WaitListTimerTask extends TimerTask { private WaitList waitList; public WaitListTimerTask(WaitList waitList){ this.waitList=waitList; } @Override public void run() { // 參數waitList使用示例 List<CourseWaitList> allCourseWaitList = this.waitList.getAllCourseWaitList(); } }
import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimerTask; public class WaitListTimerTask extends TimerTask { private WaitList waitList; public WaitListTimerTask(WaitList waitList){ this.waitList=waitList; } @Override public void run() { // 參數waitList使用示例 List<CourseWaitList> allCourseWaitList = this.waitList.getAllCourseWaitList(); } }
Spring3.0之後自主開發了定時任務工具spring task,能夠將它比做一個輕量級的Quartz,並且使用起來很簡單,除spring相關的包外不須要額外的包,並且支持註解和配置文件兩種形式,下面將分別介紹這兩種方式。
第一種:配置文件方式
①編寫做業類
即普通的pojo,以下:
import org.springframework.stereotype.Service; @Service public class TaskJob { public void job1() { System.out.println(「任務進行中。。。」); } }
import org.springframework.stereotype.Service; @Service public class TaskJob { public void job1() { System.out.println(「任務進行中。。。」); } }
②在spring配置文件頭中添加命名空間及描述
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:task="http://www.springframework.org/schema/task" …… xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
③Spring配置文件中設置具體的任務
<task:scheduled-tasks> <task:scheduled ref="taskJob" method="job1" cron="0 * * * * ?"/> </task:scheduled-tasks> <context:component-scan base-package=" com.gy.mytask " />
說明:ref參數指定的即任務類,method指定的即須要運行的方法,cron及cronExpression表達式,具體寫法這裏不介紹了,詳情見附錄。
<context:component-scan base-package="com.gy.mytask" />這個配置根據項目實際狀況調整包的位置,spring掃描註解用的。
第二種:使用註解形式
①編寫做業類
即普通的pojo,以下:
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component(「taskJob」) public class TaskJob { @Scheduled(cron = "0 0 3 * * ?") public void job1() { System.out.println(「任務進行中。。。」); } }
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component(「taskJob」) public class TaskJob { @Scheduled(cron = "0 0 3 * * ?") public void job1() { System.out.println(「任務進行中。。。」); } }
注意:此處@Schedule註解有三個方法或者叫參數,分別表示的意思是:
cron:指定cron表達式
fixedDelay:即表示從上一個任務完成開始到下一個任務開始的間隔,單位是毫秒。
fixedRate:即從上一個任務開始到下一個任務開始的間隔,單位是毫秒。
②添加task相關的配置
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/jdbc/spring-jdbc-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/task http://www.springframework.org/schema/task/spring-task-3.0.xsd" default-lazy-init="false"> <context:annotation-config /> <!—spring掃描註解的配置 --> <context:component-scan base-package="com.gy.mytask" /> <!—開啓這個配置,spring才能識別@Scheduled註解 --> <task:annotation-driven scheduler="qbScheduler" mode="proxy"/> <task:scheduler id="qbScheduler" pool-size="10"/>
說明:理論上只須要加上《task:annotation-driven /》這句配置就能夠了,這些參數都不是必須的。
Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,它能夠與J2EE與J2SE應用程序相結合也能夠單獨使用。Quartz能夠用來建立簡單或爲運行十個,百個,甚至是好幾萬個Jobs這樣複雜的程序。Jobs能夠作成標準的Java組件或 EJBs。Quartz的最新版本爲Quartz 2.2.2。下面將介紹兩種Quartz使用方式:
第一種:做業類繼承自特定的基類
org.springframework.scheduling.quartz.QuartzJobBean
①編寫做業類
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; public class Job1 extends QuartzJobBean { private int timeout; private static int i = 0; //調度工廠實例化後,通過timeout時間開始執行調度 public void setTimeout(int timeout) { this.timeout = timeout; } /** * 要調度的具體任務 */ @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { System.out.println("定時任務執行中…"); } }
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; public class Job1 extends QuartzJobBean { private int timeout; private static int i = 0; //調度工廠實例化後,通過timeout時間開始執行調度 public void setTimeout(int timeout) { this.timeout = timeout; } /** * 要調度的具體任務 */ @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { System.out.println("定時任務執行中…"); } }
②spring配置文件中配置做業類JobDetailBean
<bean name="job1" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="com.gy.Job1" /> <property name="jobDataAsMap"> <map> <entry key="timeout" value="0" /> </map> </property> </bean>
說明:org.springframework.scheduling.quartz.JobDetailBean有兩個屬性,jobClass屬性即咱們在java代碼中定義的任務類,jobDataAsMap屬性即該任務類中須要注入的屬性值。
③配置做業調度的觸發方式(觸發器)
Quartz的做業觸發器有兩種,分別是
org.springframework.scheduling.quartz.SimpleTriggerBean
org.springframework.scheduling.quartz.CronTriggerBean
第一種SimpleTriggerBean,只支持按照必定頻度調用任務,如每隔30分鐘運行一次。
配置方式以下:
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="job1" /> <!-- 調度工廠實例化後,通過0秒開始執行調度 --> <property name="startDelay" value="0" /> <!-- 每2秒調度一次 --> <property name="repeatInterval" value="2000" /> </bean>
第二種CronTriggerBean,支持到指定時間運行一次,如天天12:00運行一次等。
配置方式以下:
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="job1" /> <!—天天12:00運行一次 --> <property name="cronExpression" value="0 0 12 * * ?" /> </bean>
④配置調度工廠
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> </bean>
說明:該參數指定的就是以前配置的觸發器的名字。
⑤啓動你的應用便可,即將工程部署至tomcat或其餘容器。
第二種:做業類不繼承特定基類(推薦使用)
Spring可以支持這種方式,歸功於兩個類:
org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean
org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
這兩個類分別對應spring支持的兩種實現任務調度的方式,即前文提到到java自帶的timer task方式和Quartz方式。這裏我只寫MethodInvokingJobDetailFactoryBean的用法,使用該類的好處是,咱們的任務類再也不須要繼承自任何類,而是普通的pojo。
①編寫做業類(普通POJO)
public class Job2 { public void doJob2() { System.out.println("不繼承QuartzJobBean方式-調度進行中..."); } }
public class Job2 { public void doJob2() { System.out.println("不繼承QuartzJobBean方式-調度進行中..."); } }
②配置做業類
<bean id="job2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject"> <bean class="com.gy.Job2" /> </property> <property name="targetMethod" value="doJob2" /> <!-- 做業不併發調度 --> <property name="concurrent" value="false" /> </bean>
說明:這一步是關鍵步驟,聲明一個MethodInvokingJobDetailFactoryBean,有兩個關鍵屬性:targetObject指定任務類,targetMethod指定運行的方法。
③配置做業調度的觸發方式(觸發器)
Quartz的做業觸發器有兩種,分別是
org.springframework.scheduling.quartz.SimpleTriggerBean
org.springframework.scheduling.quartz.CronTriggerBean
第一種SimpleTriggerBean,只支持按照必定頻度調用任務,如每隔30分鐘運行一次。
配置方式以下:
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="job1" /> <!-- 調度工廠實例化後,通過0秒開始執行調度 --> <property name="startDelay" value="0" /> <!-- 每2秒調度一次 --> <property name="repeatInterval" value="2000" /> </bean>
第二種CronTriggerBean,支持到指定時間運行一次,如天天12:00運行一次等。
配置方式以下:
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="job1" /> <!—天天12:00運行一次 --> <property name="cronExpression" value="0 0 12 * * ?" /> </bean>
④配置調度工廠
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> </bean>
說明:該參數指定的就是以前配置的觸發器的名字。
⑤啓動你的應用便可,即將工程部署至tomcat或其餘容器。
①配置多個定時器任務
<util:properties id="applicationProps" location="classpath:enroll.properties" /> <context:property-placeholder properties-ref="applicationProps" /> <bean id="waitListExpireJob" class="com.yunteng.ngtl.enroll.tool.waitListExpireTaskJob" /> <bean id="expireJobTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="waitListExpireJob" /> <property name="targetMethod" value="expireProcess" /> </bean> <bean id="waitListExpireTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="name" value="waitListExpireTriggerName" /> <property name="group" value="waitListExpireTriggerGroup" /> <property name="jobDetail"> <ref bean="expireJobTask" /> </property> <property name="cronExpression"> <value>#{applicationProps['cron.expireTask']}</value> </property> </bean> <bean id="waitListObserveJob" class="com.yunteng.ngtl.enroll.tool.waitListObserveTaskJob" /> <bean id="observeJobTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="waitListObserveJob" /> <property name="targetMethod" value="observeProcess" /> </bean> <bean id="waitListObserveTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="name" value="waitListObserveTriggerName" /> <property name="group" value="waitListObserveTriggerGroup" /> <property name="jobDetail"> <ref bean="observeJobTask" /> </property> <property name="cronExpression"> <value>#{applicationProps['cron.observeTask']}</value> </property> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref local="waitListExpireTrigger" /> <ref local="waitListObserveTrigger" /> </list> </property> </bean>
②動態修改定時器任務調度時間週期(關鍵字:quartz change cron expression runtime)
注意:目前只在Quartz1.8.6版本下測試成功
CronTrigger cronTrigger = (CronTrigger) stdScheduler.getTrigger(triggerName,triggerGroupName); cronTrigger.setCronExpression(newCronExpression); stdScheduler.rescheduleJob(triggerName,triggerGroupName,cronTrigger);
CronTrigger cronTrigger = (CronTrigger) stdScheduler.getTrigger(triggerName,triggerGroupName); cronTrigger.setCronExpression(newCronExpression); stdScheduler.rescheduleJob(triggerName,triggerGroupName,cronTrigger);
3 總結與分析
~ | Timer | Spring-Task | Quartz |
---|---|---|---|
做業類的繼承方式 | java.util.Timer中須要繼承自java.util.TimerTask | 普通的java類,不須要繼承其餘類 | 繼承自org.springframework.scheduling.quartz.QuartzJobBean |
是否可使用Cron表達式 | 不能夠 | 能夠 | 能夠 |
動態改變執行時間週期 | 能夠,可是使用不靈活 | 資料太少,未找到相關方法 | 能夠,將觸發器從新啓動便可從新調度任務(資料較多,目前只在Quartz1.8.6版本測試經過) |
使用難易程度 | 簡單 | 簡單 | 稍難,須要配置的部分相對較多且繁瑣 |
這篇博文到這裏就結束了,但願下次有時間能夠多添加一些圖表等更加形象的內容。