Spring提供的三种定时任务机制及其比较

定时任务的需求在众多应用系统中广泛存在,在Spring中,我们可以使用三种不同的定时机制,下面一一描述并加以比较

1. 基于Quartz的定时机制

下面详细解释这个类图中涉及的关键类及其使用场景

1.1. SchedulerFactoryBean

这是Spring中基于Quartz的定时机制入口,只要Spring容器装载了这个类,Quartz定时机制就会启动,并加载定义在这个类中的所有trigger

Spring配置范例:

    <bean id="sfb" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 添加触发器 -->
<property name="triggers">
<list>
<ref local="appSubscTrigger" />
</list>
</property> <!-- 添加listener -->
<property name="globalTriggerListeners">
<list>
<ref local="myTaskTriggerListener" />
</list>
</property>
</bean>

1.2. CronTriggerBean

实现了Trigger接口,基于Cron表达式的触发器

这种触发器的好处是表达式与linux下的crontab一致,能够满足非常复杂的定时需求,也容易配置

Spring配置范例:

<bean id="notifyTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="notifyJobDetail" />
<property name="cronExpression" value="${notify_trigger_cron_expression}" />
</bean>

1.3. SimpleTriggerBean

该类也实现了Trigger接口,基于配置的定时调度

这个触发器的优点在于很容易配置一个简单的定时调度策略

Spring配置范例

    <bean id="simpleReportTrigger"   class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail">
<ref bean="reportJob"/>
</property>
<property name="startDelay">
<value>3600000</value>
</property>
<property name="repeatInterval">
<value>86400000</value>
</property>
</bean>

1.4. JobDetailBean

JobDetail类的简单扩展,能够包装一个继承自QuartzJobBean的普通Bean,使之成为定时运行的Job

缺点是包装的Bean必须继承自一个指定的类,通用性不强,对普通Job的侵入性过强,不推荐使用

1.5. MethodInvokingJobDetailFactoryBean

Spring提供的一个不错的JobDetail包装工具,能够包装任何bean,并执行类中指定的任何stati或非static的方法,避免强制要求bean去实现某接口或继承某基础类

    <bean id="notifyJobDetail" parent="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="notifyServerHandler" />
<property name="targetMethod" value="execute" />
</bean>

1.6. 关于TriggerListener和JobListener

Quartz中提供了类似WebWork的拦截器的功能,系统执行任务前或任务执行完毕后,都会检查是否有对应的Listener需要被执行,这种AOP的思想为我们带来了灵活的业务需求实现方式。

例如现在有一个简单的业务要求:任务执行前先判断当前服务器是否为task服务器,不是则不执行任务。对于这种业务需求,我们可以简单的实现一个 TriggerListener,并将其插入SchedulerFactoryBean的globalTriggerListeners中,这样所有的 job在执行前后都会调用TriggerListener中对应的方法。

代码范例:

public class MyTaskTriggerListener implements TriggerListener {
protected static final Log logger = LogFactory.getLog(MyTaskTriggerListener.class); /**
* 需要运行task任务的机器列表
*/
private String taskServers; public String getName() {
return "MyTaskTriggerListener";
} public void triggerComplete(Trigger arg0, JobExecutionContext arg1, int arg2) {
} public void triggerFired(Trigger arg0, JobExecutionContext arg1) {
} public void triggerMisfired(Trigger arg0) {
} /**
* 判断当前服务器是否为task服务器,来决定是否执行task
* @return
*/
public boolean vetoJobExecution(Trigger arg0, JobExecutionContext arg1) {
String serverName;
try {
serverName = InetAddress.getLocalHost().getHostName();//获取主机名
} catch (UnknownHostException e) {
e.printStackTrace();
return true;
}
if (taskServers.indexOf(serverName) > -1) {
if (logger.isInfoEnabled()) {
logger.info("this is a task server, job will be executed");
}
return false;
} else {
if (logger.isInfoEnabled()) {
logger.info("this is not a task server, job will be vetoed");
}
return true;
}
} public String getTaskServers() {
return taskServers;
} public void setTaskServers(String taskServers) {
this.taskServers = taskServers;
}
}

2. 基于Timer的定时机制

JDK提供了基础的定时类:Timer,在这个类的基础上,Spring提供了一套简单的定时机制

下面详细解释这个类图中涉及的关键类及其使用场景

2.1. TimerFactoryBean

这个类非常类似Quartz中的SchedulerFactoryBean,是基于Timer的定时机制的入口,Spring容器装载此类后会自动开始定时器

Spring配置范例:

<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTask" />
</list>
</property>
</bean>

2.2. ScheduledTimerTask

类似于Quartz中的Trigger的SimpleTriggerBean实现,任务是在设定的时间触发并执行配置的任务,特点是配置简单、明了,使用于简单的任务触发逻辑

Spring配置范例:

<bean id=”scheduledReportTask” class=”org.springframework.scheduling.timer.ScheduledTimerTask”>
<property name=”timerTask”>
<ref bean =”reportTimerTask”/>
</property>
<property name=”period”>
<value>86400000</value>
</property>
</bean>

2.3. TimerTask抽象类

普通task实现必须要继承的父类,主要包含一个run()的方法,类似Quartz中的QuartzJobBean,对应用侵入性较强,也不推荐使用

2.4. MethodInvokingTimerTaskFactoryBean

类似Quartz中的MethodInvokingJobDetailFactoryBean,用于封装任何bean,并可以执行bean中的任意方法,不再复述

3. 基于Executor的定时机制

这种定时机制与上面两种定时机制没有太大区别,特别是在配置和实现功能上,不同的是它的核心是基于ScheduledExecutorService(ScheduledThreadPoolExecutor是默认实现),一种JDK5.0中提供的基于线程的并发机制,关于JDK5中的线程池的概念及其一些深入分析,请参考老唐的博客:http://blog.csdn.net/sfdev/archive/2008/12/30/3648457.aspx 这里不再复述

4. 三种定时机制的比较和案例分析

看完了这三种定时机制,各有各的优劣,不同场景下我们应该灵活选择不同的定时机制。总的来说,如果我们需要简单的定时器,我们可以选用基于 timer的定时器,如果定时规则较为复杂,我们可以选用基于Quartz的定时器,如果我们要用到线程池来处理异步任务,我们可以选用基于 Executor的定时机制,虽然只是任务实现中用到线程池,毕竟也是一脉相承的,当然也可以用Quartz的定时器+基于Executor的任务线程 池,完全没有任何冲突的。

说这么多,还是比较抽象,不如我们来分析一下老唐的Notify系统来加深对Spring定时机制的了解(详细设计参考最近一期的程序员杂志)。

在老唐的Notify系统中,完全使用了基于JDK5.0中的Executor的定时机制,即由一个 ScheduledExecutorFactoryBean触发系统的每隔2分钟运行一个单线程的任务,在这个任务中,执行完各种机制检查和配置策略后, 将要执行的Notify任务放入一个已配置好的线程池,并由线程池指定线程来完成Notify的任务。

在最近一期的项目中,我们将task移植到了apps,Notify系统也同时被移植过来了,为了统一所有的task,我们将以前task中基于 timer、Quartz和Executor的各种任务统一改为基于Quartz的调度。在这个过程中,Notify系统的基于Executor的定时机 制也被改为基于Quartz的定时机制,过程非常顺利。基于这次移植项目,可以说这三种定时机制是非常容易互换的,并且通用性比较强,只需要简单的配置即 可。

转自:http://blog.csdn.net/52rainbow/article/details/4004206

spring-定时器(2)的更多相关文章

  1. spring定时器,定时器一次执行两次的问题

    Spring 定时器 方法一:注解形式 配置文件头加上如下: xmlns:task="http://www.springframework.org/schema/task" htt ...

  2. Spring 定时器Quartz的用法

    Spring定时器Quartz的用法也很简单,需要引入quartz-all-1.5.2.jar java代码如下: package com.coalmine.desktop; import java. ...

  3. spring定时器,当遇见半小时的情况时

    spring定时器遇见半小时的解决方法(这里只提供注解方式) @Scheduled(fixedRate=6000000)//每隔100分钟执行方法 fixedRate的值是毫秒

  4. Spring 定时器的使用

    spring定时器应用 相关类: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 配置定时远行方法 o ...

  5. spring定时器

    本人小菜鸟一枚,今天在公司看到一段spring定时器配置,自己总结一下! <!-- 定义调用对象和调用对象的方法 --><bean id="jobtask9" c ...

  6. 两种流行Spring定时器配置:Java的Timer类和OpenSymphony的Quartz

    1.Java Timer定时 首先继承java.util.TimerTask类实现run方法 import java.util.TimerTask; public class EmailReportT ...

  7. 注解式开发spring定时器

    1:spring 配置文件中增加这句    <task:annotation-driven/>  2:确保扫描程序能够扫描后  下面第3步骤的java类    <context:co ...

  8. spring定时器设置(转自:http://my.oschina.net/LvSantorini/blog/520049)

    转自:http://my.oschina.net/LvSantorini/blog/520049<!-- MessageRequestTask类中包含了msgRequest方法,用于执行定时任务 ...

  9. spring定时器,5步完成

    spring定时器,5步完成,我们开发的时候会用定时执行任务. 用spring框架时,可以直接使用spring定时功能 1.创建任务调度类,里面一个方法,方法名为work 2. spring配置文件, ...

  10. spring定时器用Annotation兑现

    spring定时器用Annotation实现 0人收藏此文章, 我要收藏发表于3个月前 , 已有46次阅读 共0个评论 1.ApplicationContext.xml配置 a).需要在xmlns里面 ...

随机推荐

  1. EDP转换IC NCS8801S:RGB/LVDS转EDP芯片

    RGB/LVDS-to-eDP Converter1 Features    Embedded-DisplayPort (eDP) Output    2-lane/4-lane eDP @ 1.62 ...

  2. JavaScript之作用域与闭包总结

    博主最开始接触程序是C语言,C++,后来是java,现在是php,无论哪一种语言与javascript在机制上都还是有比较大的区别. 下面总结一下用面向对象的思想写javascript需要区分的要点: ...

  3. 机器学习-scikit learn学习笔记

    scikit-learn官网:http://scikit-learn.org/stable/ 通常情况下,一个学习问题会包含一组学习样本数据,计算机通过对样本数据的学习,尝试对未知数据进行预测. 学习 ...

  4. 在Caffe中实现模型融合

    模型融合 有的时候我们手头可能有了若干个已经训练好的模型,这些模型可能是同样的结构,也可能是不同的结构,训练模型的数据可能是同一批,也可能不同.无论是出于要通过ensemble提升性能的目的,还是要设 ...

  5. C# 超高速高性能写日志 代码开源

    1.需求 需求很简单,就是在C#开发中高速写日志.比如在高并发,高流量的地方需要写日志.我们知道程序在操作磁盘时是比较耗时的,所以我们把日志写到磁盘上会有一定的时间耗在上面,这些并不是我们想看到的. ...

  6. onclick = xxx这种赋值写法绑定事件的原理是什么?

    本文转自知乎貘吃馍香的回答 提问:刚入门不久,能力有限,这个问题我描述起来有点困难,只有劳烦各位大神细看了 我之前一直以为js底层存在类似下面这样的代码: //给所有dom对象定义好onclick值为 ...

  7. Broker节点

    在druid集群环境中 broker节点的作用是查询.它知道metadata 通过zookeeper发送到了集群中的哪个节点,从而能够准确的查询到.broker也把各个节点的结果汇聚到一个节点中.On ...

  8. C++ 头文件系列(system_error)

    1.为什么system_error "....report error conditions originating from the operating system or low-lev ...

  9. 什么是Actor

    本文已.Net语法为主,同时写有Scala及Java实现代码 严肃的说,演员是一个广泛的概念,作为外行人我对Actor 模型的定义: Actor是一个系统中参与者的虚拟人物,Actor与Actor之间 ...

  10. 【原创】bootstrap框架的学习 第五课

    一.Bootstrap 中定义了所有的 HTML 标题(h1 到 h6)的样式. <!DOCTYPE html> <html> <head> <title&g ...