spring提供的三种定时任务

来源:互联网 发布:mac哑光修容粉怎么选 编辑:程序博客网 时间:2024/05/18 16:39

在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.xsd                http://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

2 0
原创粉丝点击