JDK的標準API中所提供的Timer功能有限,只能指定任務與任務之間的期間(Period),無法指定某個時間點定時執行任務,您可以使用Quartz,它提供了更多的排程功能,而Spring則對Quartz進行了封裝,讓它在使用上更加方便。
您可以繼承org.springframework.scheduling.quartz.QuartzJobBean來實作一個Job類別,例如:
package onlyfun.caterpillar;
import org.quartz.JobExecutionContext; import org.springframework.scheduling. quartz.QuartzJobBean;
public class DemoJob extends QuartzJobBean { private JobData jobData; public void executeInternal( JobExecutionContext context) { System.out.println( jobData.getData() + " is executed."); } public void setJobData(JobData jobData) { this.jobData = jobData; } public JobData getJobData() { return jobData; } }
JobData只是一個Job資料物件的示範類別,為了能看出排程Job被執行時的週期性,它會傳回一個Date物件表示執行Job時所需資料的傳回時間,例如:
package onlyfun.caterpillar;
import java.util.Date;
public class JobData { public String getData() { return "Data from " + new Date().toString(); } }
直接來看定義檔如何定義:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="someData" class="onlyfun.caterpillar.JobData"/>
<bean id="jobDetailBean" class="org.springframework.scheduling. → quartz.JobDetailBean"> <property name="jobClass"> <value>onlyfun.caterpillar.DemoJob</value> </property> <property name="jobDataAsMap"> <map> <entry key="jobData"> <ref bean="someData"/> </entry> </map> </property> </bean>
<bean id="simpleTriggerBean" class="org.springframework.scheduling. → quartz.SimpleTriggerBean"> <property name="jobDetail"> <ref bean="jobDetailBean"/> </property> <property name="repeatInterval"> <value>1000</value> </property> <property name="startDelay"> <value>1000</value> </property> </bean> <bean id="schedulerFactoryBean" class="org.springframework.scheduling. → quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="simpleTriggerBean"/> </list> </property> </bean> </beans>
在以上設定中比較特別要注意的是,
org.springframework.scheduling.quartz.JobDetailBean的"jobClass"屬性必須提供Job的
類別名稱,而不是Job的Bean實例,而Job所需的資料可以在"jobDataAsMap"屬性中來提供。
在排程任務的週期指定上,使用org.springframework.scheduling.quartz.SimpleTriggerBean來指
定,這點與 TimerTask
排程中的指定方式類似,指定的時間同樣也是以毫秒作為單位,而排定Job時,所使用的是
org.springframework.scheduling.quartz.SchedulerFactoryBean。
完成設定之後,只要啟動Spring並讀取定義檔完成後,排程任務就會進行,例如撰寫一個簡單的任務啟動類別:
package onlyfun.caterpillar;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.springframework.context. support.FileSystemXmlApplicationContext;
public class QuartzDemo { public static void main(String[] args) throws IOException { new FileSystemXmlApplicationContext("beans-config.xml"); System.out.println("啟動 Task.."); System.out.println("請輸入 exit 關閉 Task: "); BufferedReader reader = new BufferedReader( new InputStreamReader(System.in)); while(true) { if(reader.readLine().equals("exit")) { System.exit(0); } } } }
使用SimpleTriggerBean只能作簡單的Job與Job之間執行的期間(Period)指定,如果要直接作時間點的指定,則可以使用org.springframework.scheduling.quartz.CronTriggerBean,例如:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="someData" class="onlyfun.caterpillar.JobData"/>
<bean id="jobDetailBean" class="org.springframework.scheduling. → quartz.JobDetailBean"> <property name="jobClass"> <value>onlyfun.caterpillar.DemoJob</value> </property> <property name="jobDataAsMap"> <map> <entry key="jobData"> <ref bean="someData"/> </entry> </map> </property> </bean>
<bean id="cronTriggerBean" class="org.springframework.scheduling. → quartz.CronTriggerBean"> <property name="jobDetail"> <ref bean="jobDetailBean"/> </property> <property name="cronExpression"> <value>0 0 19 * * ?</value> </property> </bean> <bean id="schedulerFactoryBean" class="org.springframework.scheduling. → quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTriggerBean"/> </list> </property> </bean> </beans>
重點在於"cronExpression"屬性的指定,指定的格式是至少六個時間元素,最多七個時間元素,例如上面的指定是每天的19時要執行Job一次,"cronExpression"屬性指定的格式如下:
- 秒(0-59)
- 分(0-59)
- 小時(0-23)
- 每月第幾天(1-31)
- 月(1-12或JAN-DEC)
- 每星期第幾天(1-7或SUN-SAT)
- 年(1970-2099)
其中「每月第幾天」與「每星期第幾天是互斥」的,兩個只能設定一個,不設定的以 ? 符號撰寫,如果有好幾個時間點,可以使用 , 符號,例如:「0
0 10,12,14 * * ?」表示每天的10時、12時、14時要執行Job;對於連續的時間可以使用 - 符號,例如「0 0
10,12,14 1-15 * ?」表示每月的1到15日每10時、12時、15時要執行Job,時間格式中的年指定可有可無,例如:「0 0
10,12,14 ? * MON 2006」表示2006年每星期一的10時、12時、14時要執行Job。
|