ITEEDU

使用 Quartz

JDK的标准API中所提供的Timer功能有限,只能指定任务与任务之间的期间(Period),无法指定 某个时间点定时执行任务,您可以使用Quartz,它提供了更多的排程功能,而Spring则对Quartz 进行了封装,让它在使用上更加方便。

您可以继承org.springframework.scheduling.quartz.QuartzJobBean来实作一个Job类别,例如:

•      DemoJob.java
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 时所需资料的传回时间,例如:

•      JobData.java
package onlyfun.caterpillar;
import java.util.Date;
public class JobData {
	public String getData() {
		return "Data from "
			+ new Date().toString();
	}
}

直接来看定义档如何定义:

•      beans‐config.xml
<?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 并读取定义档完成后,排程任务就会进行,例如撰写一个简单 的任务启动类别:

•      QuartzDemo.java
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,例如:

•      beans‐config.xml
<?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。