视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Spring提供的三种定时任务机制及其比较
2025-09-30 23:22:49 责编:小OO
文档
  

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

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

1. 基于Quartz的定时机制

 

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

1.1. SchedulerFactoryBean

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

 

Spring配置范例:

[xhtml] view plaincopy

1.  

2.   

3.   

4.    

5.     

6.    

7.   

8.          

9.   

10.   

11.    

12.     

13.    

14.   

15.  

1.2. CronTriggerBean

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

 

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

 

Spring配置范例:

[xhtml] view plaincopy

1.  

2.   

3.   

4.  

1.3. SimpleTriggerBean

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

 

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

 

Spring配置范例:

[xhtml] view plaincopy

1.   

2.    

3.     

4.    

5.    

6.  3600000   

7.    

8.    

9.  800000   

10.    

11.  

 

1.4. JobDetailBean

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

 

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

1.5. MethodInvokingJobDetailFactoryBean

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

 

Spring配置范例:

[xhtml] view plaincopy

1.  

2.   

3.   

4.  

 

 

1.6. 关于TriggerListener和JobListener

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

 

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

 

代码范例:

[java] view plaincopy

1.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, int arg2) {  

14.    }  

15.  

16.    public void triggerFired(Trigger arg0, JobExecutionContext arg1) {  

17.    }  

18.  

19.    public void triggerMisfired(Trigger arg0) {  

20.    }  

21.  

22.    /** 

23.     * 判断当前服务器是否为task服务器,来决定是否执行task 

24.     * @return 

25.     */  

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.                logger.info("this is a task server, job will be executed");  

37.            }  

38.            return false;  

39.        } else {  

40.            if (logger.isInfoEnabled()) {  

41.                logger.info("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 plaincopy

1.  

2.   

3.    

4.     

5.    

6.   

7.  

 

2.2. ScheduledTimerTask

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

 

Spring配置范例:

[xhtml] view plaincopy

1.  

2.   

3.    

4.   

5.   

6.  800000  

7.   

8.  

 

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/38457.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的定时机制,过程非常顺利。基于这次移植项目,可以说这三种定时机制是非常容易互换的,并且通用性比较强,只需要简单的配置即可。下载本文

显示全文
专题