在spring中我们有三种不同的定时任务:基于Quartz的定时机制、基于Timer的定时机制、基于Executor的定时机制。

1、基于Quartz的定时任务机制

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

1.1. SchedulerFactoryBean

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

1.2. CronTriggerBean

实现了Trigger接口,基于Cron表达式的触发器。这种触发器的好处是表达式与linux下的crontab一致,能够满足非常复杂的定时需求,也容易配置

1.3. MethodInvokingJobDetailFactoryBean

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

Spring配置实例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"><bean id="jobDetail_1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><property name="targetObject"><ref bean="TSupeviseServiceImpl" /></property><property name="targetMethod"><value>processTInterface</value><!-- 处理数据到业务督办表T_Interface中 --></property></bean><bean id="cronTrigger_1" class="org.springframework.scheduling.quartz.CronTriggerBean"><property name="jobDetail"><ref bean="jobDetail_1" /></property><property name="cronExpression"><value>0 0 10 * * ? *</value><!-- 每天上午10点执行 --></property></bean><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="triggers"><list><ref local="cronTrigger_1" /></list></property></bean></beans>

1.4. 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.5. JobDetailBean

JobDetail类的简单扩展,能够包装一个继承自QuartzJobBean的普通Bean,使之成为定时运行的Job..缺点是包装的Bean必须继承自一个指定的类,通用性不强,对普通Job的侵入性过强,不推荐使用。

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;   }
}
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;}
}

quartz表达式解析

2、基于Timer的定时机制

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

2.1. TimerFactoryBean

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

2.2. ScheduledTimerTask

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

2.3. TimerTask抽象类

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

2.4. MethodInvokingTimerTaskFactoryBean

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

简单实例:

MyTask.java


package com.lmb.springstudy.schedule.timer;public class MyTask {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void run() {System.out.println("Run this task: " + name + ".");}}

Spring-timer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"default-lazy-init="true"><bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean" lazy-init="false"><property name="scheduledTimerTasks"><list><ref local="scheduledTask1"/><ref local="scheduledTask2"/></list></property></bean><bean id="scheduledTask1" class="org.springframework.scheduling.timer.ScheduledTimerTask"><property name="delay" value="0" /><property name="period" value="10000" /><property name="timerTask"><ref bean="methodInvokingTask1"/></property></bean><bean id="scheduledTask2" class="org.springframework.scheduling.timer.ScheduledTimerTask"><property name="delay" value="0" /><property name="period" value="10000" /><property name="timerTask"><ref bean="methodInvokingTask2"/></property></bean><bean id="methodInvokingTask1" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"><property name="targetObject" ref="myTask1"/><property name="targetMethod" value="run"/></bean><bean id="methodInvokingTask2" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"><property name="targetObject" ref="myTask2"/><property name="targetMethod" value="run"/></bean><bean id="myTask1" class="org.garbagecan.springstudy.schedule.timer.MyTask"><property name="name" value="task1"/></bean><bean id="myTask2" class="org.garbagecan.springstudy.schedule.timer.MyTask"><property name="name" value="task2"/></bean>
</beans>

原理解析:

  1. 定义了两个task,task1和task2;
  2. 利用spring提供的MethodInvokingTimerTaskFactoryBean类来实现来实现对对task类和方法的声明,声明目标对象和方法,从而使spring知道要运行那个类的那个方法;
  3. 利用ScheduledTimerTask类来配置每个task的启动时间延时,每次启动之间的间隔,当然还有最重要的是需要运行那个对象,这里使用的上面提到的MethodInvokingTimerTaskFactoryBean类的实例;
  4. 最后定义了一个TimerFactoryBean类,并且把ScheduledTimerTask类的实例作为需要调度的task;

Test.java

package lmb.springstudy.schedule.timer;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) throws Exception {new ClassPathXmlApplicationContext("/com/lmb/springstudy/schedule/timer/spring-timer.xml");}
}

Test测试类运行结果:两个task都会启动,并且都以同样的10s作为每次运行的时间间隔。

3、基于Executor的定时机制

这种定时机制与上面两种定时机制没有太大区别,特别是在配置和实现功能上,不同的是它的核心是基于ScheduledExecutorService(ScheduledThreadPoolExecutor是默认实现),一种JDK5.0中提供的基于线程的并发机制。关于Executor的详细内容请参看博主的另一篇文章。

如果需要简单的定时器可以选用基于Timer的定时机制,如果需要较复杂的定时器可以选用基于Quartz的定时机制,如果我们要用到线程池来处理异步任务,我们可以选用基于Executor的定时机制,虽然只是任务实现中用到线程池,毕竟也是一脉相承的,当然也可以用Quartz的定时器+基于Executor的任务线程池,完全没有任何冲突的。

有关Executor的详细内容,请参看本人的以下文章:http://blog.csdn.net/lmb55/article/details/50555309

【Spring学习】spring提供的三种定时任务相关推荐

  1. Spring实战(三)Spring中装配Bean的三种方式---XML、JavaConfig、AutoWire

    创建应用对象之间协作关系的行为称为装配(wiring),这也是依赖注入的本质. Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系,而开发者需要告诉Spring需要创建哪些 ...

  2. 计算机内部组件三种电压,电源通常向计算机内部的各种组件提供哪三种电压

    此资源收集于兔客源码网www.tukebbs.com 电源通常向计算机内部的各种组件提供的三种电压:1.5V,主要供给主板:2.3.3V,主要为CPU供电:3.正负12V,主要为音频电路,硬盘供电.计 ...

  3. “前端开发中的三种定时任务及其应用“

    前端定时任务是指在一定时间间隔内,自动执行指定的操作或函数.在前端开发中,定时任务被广泛应用于诸如数据更新.定时提醒.定时刷新页面等方面.在本文中,我们将介绍前端中常见的三种定时任务,分别是 setT ...

  4. Comsol学习笔记1:三种瞬态求解器的选择

    最近在求解一个瞬态问题,计算结果不收敛.研究了一下comsol提供的三种瞬态求解器. 1,向后差分公式BDF 稳定性是它的最大优势.它一种使用向后差分公式的隐式求解器,其精度在一阶(也称为向后欧拉法) ...

  5. 网络上连接的计算机必须要安装,[单选] Windows XP中提供了三种组件,实现不同的网络功能。如果计算机需要连接到Internet,必须安装()。...

    [单选] Windows XP中提供了三种组件,实现不同的网络功能.如果计算机需要连接到Internet,必须安装(). 更多相关问题 [单选] 乙炔与空气或氧气混合达到自燃温度在()下也能爆炸 [单 ...

  6. Spring 3.0 学习-环境搭建和三种形式访问

    理论学习 ·PO(persistent object)是持久化对象,所谓的持久化就是和数据库对应的主要是字段上,典型的应用是在hibernate中通过实体对象直接操作数据库的增删查改.一般提供get. ...

  7. java 循环依赖_浅谈Spring解决循环依赖的三种方式

    引言:循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错.下面说一下Spring是如果解决循环依赖的. 第一种: ...

  8. Spring Boot 注册 Servlet 的三种方法,真是太有用了!

    2019独角兽企业重金招聘Python工程师标准>>> 本文栈长教你如何在 Spring Boot 注册 Servlet.Filter.Listener. 你所需具备的基础 什么是 ...

  9. Spring Boot项目(Maven\Gradle)三种启动方式及后台运行详解

    Spring Boot项目三种启动方式及后台运行详解 1 Spring Boot项目三种启动方法 运行Application.java类中的Main方法 项目管理工具启动 Maven项目:mvn sp ...

最新文章

  1. 用GPU拯救世界:英伟达斯坦福呼吁玩家捐献算力,投入新冠病毒相关蛋白质分布式计算...
  2. 【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )
  3. 冷却负载、人为因素影响传统数据中心效率
  4. Javascript称球
  5. 重学java基础第二十五课:数据类型
  6. js+css实现验证码框,前端实现6位验证码输入框效果
  7. C++ 构造函数与析构函数
  8. Linux命令行设置环境变量
  9. python编程出现:expected an indented block错误。
  10. 安卓ROOT全教程(测试机 红米Note7Pro)
  11. Python语言程序设计基础_序列型数据和控制结构综合练习(第七周)_答案_通识教育必修课程_上海师范大学
  12. vue-loader was used without the corresponding plugin.
  13. Google earth engine(GEE):基于MODIS的LST(地表温度数据)计算一定时间序列的城市热岛强度(UHI),并绘制直方图
  14. 计算计控制系统2.0
  15. 三元前驱体废水除镍钴锰
  16. 本征半导体的导电机制 空穴的概念
  17. 【NVIDIA】 CUDA Toolkit工具包下载
  18. STC-ISP 串口打开失败,请检查指定串口
  19. radmin显示不能连接到服务器,关于Radmin安装失败或无法显示远程桌面的处理方法...
  20. Windows XP启动过程及常见启动故障

热门文章

  1. Excel生成报表之解决方案--设置单个单元格格式
  2. Android studio怎么配置javadoc生成项目API
  3. Linux(内核和用户态的)动态内存管理
  4. Google AI 教育项目今起免费开放,支持中文
  5. android颜色值的表示方法android:background=#FFFFFFFF的意思
  6. 为什么vue前端项目要使用nodejs
  7. tesseract-ocr的安装及使用
  8. 在终端显示文本的中间部分
  9. python pdb 调试
  10. 一款可视化的在线制作H5