Spring提供的三种定时任务机制及其比较定时任务的需求在众多应用系统中广泛存在,在Spring中,我们可以使用三种不同的定时机制,下面一一描述并加以比较1. 基于Quartz的定时机制下面详细解释这个类图中涉及的关键类及其使用场景1.1. SchedulerFactoryBean这是Spring中基于Quartz的定时机制入口,只要Spring容器装载了这个类,Quartz定时机制就会启动,并加载定义在这个类中的所有triggerSpring配置范例:[xhtml]view plaincopy1.<bean id="sfb"class="org.springframework.scheduling.quartz.SchedulerFactoryBean">2.<!-- 添加触发器 -->3.<property name="triggers">4.<list>5.<ref local="appSubscTrigger"/>6.</list>7.</property>8.9.<!-- 添加listener -->10.<property name="globalTriggerListeners">11.<list>12.<ref local="myTaskTriggerListener"/>13.</list>14.</property>15.</bean>1.2. CronTriggerBean实现了Trigger接口,基于Cron表达式的触发器这种触发器的好处是表达式与linux下的crontab一致,能够满足非常复杂的定时需求,也容易配置Spring配置范例:[xhtml]view plaincopy1.<bean id="notifyTrigger"class="org.springframework.scheduling.quartz.CronTriggerBean">2.<property name="jobDetail"ref="notifyJobDetail"/>3.<property name="cronExpression"value="${notify_trigger_cron_expression}"/>4.</bean>1.3. SimpleTriggerBean该类也实现了Trigger接口,基于配置的定时调度这个触发器的优点在于很容易配置一个简单的定时调度策略Spring配置范例:[xhtml]view plaincopy1.<bean id="simpleReportTrigger"class="org.springframework.scheduling.quartz.SimpleTriggerBean">2.<property name="jobDetail">3.<ref bean="reportJob"/>4.</property>5.<property name="startDelay">6.<value>3600000</value>7.</property>8.<property name="repeatInterval">9.<value>86400000</value>10.</property>11.</bean>1.4. JobDetailBeanJobDetail类的简单扩展,能够包装一个继承自QuartzJobBean的普通Bean,使之成为定时运行的Job缺点是包装的Bean必须继承自一个指定的类,通用性不强,对普通Job的侵入性过强,不推荐使用1.5. MethodInvokingJobDetailFactoryBeanSpring提供的一个不错的JobDetail包装工具,能够包装任何bean,并执行类中指定的任何stati或非static的方法,避免强制要求bean去实现某接口或继承某基础类Spring配置范例:[xhtml]view plaincopy1.<bean id="notifyJobDetail"parent="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">2.<property name="targetObject"ref="notifyServerHandler"/>3.<property name="targetMethod"value="execute"/>4.</bean>1.6. 关于TriggerListener和JobListenerQuartz中提供了类似WebWork的拦截器的功能,系统执行任务前或任务执行完毕后,都会检查是否有对应的Listener需要被执行,这种AOP的思想为我们带来了灵活的业务需求实现方式。
例如现在有一个简单的业务要求:任务执行前先判断当前服务器是否为task服务器,不是则不执行任务。
对于这种业务需求,我们可以简单的实现一个TriggerListener,并将其插入SchedulerFactoryBean的globalTriggerListeners中,这样所有的job在执行前后都会调用TriggerListener中对应的方法。
代码范例:[java]view plaincopy1.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, intarg2) {14. }15.16.public void triggerFired(Trigger arg0, JobExecutionContext arg1) {17. }18.19.public void triggerMisfired(Trigger arg0) {20. }21.22./**23. * 判断当前服务器是否为task服务器,来决定是否执行task24. * @return25. */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. ("this is a task server, job will be executed");37. }38.return false;39. } else {40.if (logger.isInfoEnabled()) {41. ("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提供了一套简单的定时机制下面详细解释这个类图中涉及的关键类及其使用场景2.1. TimerFactoryBean这个类非常类似Quartz中的SchedulerFactoryBean,是基于Timer的定时机制的入口,Spring容器装载此类后会自动开始定时器Spring配置范例:[xhtml]view plaincopy1.<bean id="timerFactory"class="org.springframework.scheduling.timer.TimerFactoryBean">2.<property name="scheduledTimerTasks">3.<list>4.<ref bean="scheduledTask"/>5.</list>6.</property>7.</bean>2.2. ScheduledTimerTask类似于Quartz中的Trigger的SimpleTriggerBean实现,任务是在设定的时间触发并执行配置的任务,特点是配置简单、明了,使用于简单的任务触发逻辑Spring配置范例:[xhtml]view plaincopy1.<bean id=”scheduledReportTask”class=”org.springframework.scheduling.timer.ScheduledTimerTask”>2.<property name=”timerTask”>3.<ref bean=”reportTimerTask”/>4.</property>5.<property name=”period”>6.<value>86400000</value>7.</property>8.</bean>2.3. TimerTask抽象类普通task实现必须要继承的父类,主要包含一个run()的方法,类似Quartz中的QuartzJobBean,对应用侵入性较强,也不推荐使用2.4. MethodInvokingTimerTaskFactoryBean类似Quartz中的MethodInvokingJobDetailFactoryBean,用于封装任何bean,并可以执行bean中的任意方法,不再复述3. 基于Executor的定时机制这种定时机制与上面两种定时机制没有太大区别,特别是在配置和实现功能上,不同的是它的核心是基于ScheduledExecutorService(ScheduledThreadPoolExecutor是默认实现),一种JDK5.0中提供的基于线程的并发机制,关于JDK5中的线程池的概念及其一些深入分析,请参考老唐的博客:/sfdev/archive/2008/12/30/3648457.aspx这里不再复述4. 三种定时机制的比较和案例分析看完了这三种定时机制,各有各的优劣,不同场景下我们应该灵活选择不同的定时机制。