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。