`
星夜的遐想
  • 浏览: 186826 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Spring的任务调度管理

阅读更多

最近在网上看到的一片好文章,在此跟大家分享下
2012-10-17  Spring的任务调度管理 
Spring的任务调度管理 
­ 
­ 
在项目开发中,有不少程序需要定时触发。比如,统计报表程序需要在每月初运行一次,对上月份数据进行统计。而这种触发,在unix上就是使用 crontab或at命令来指定。其中at命令可以设定程序在某年某月某日、何时何分定时启动,at命令只执行一次程序。而crontab则可以设定程序在指定的时刻重复执行。在window操作系统中也有类似的命令。Window的at命令在功能上基本与unix的一致。Window控制面板中的“任务计划”与unix上从crontab类似,只是它是基于图形界面的,更人性化一些。 
在开发上一个项目时,我遇到以下这样的一个问题。项目是java+tomcat开发的,在window系统上运行,但我们没有该服务器上的管理员权限(因为该服务器上还运行着其它重要的系统,管理员只给了我们一个最低权限的帐号),无法配置“任务计划”。我们使用该功能的话,需要打申请,通过客户的系统管理员帮我们配置。考虑到我们的业务统计报表程序需要有一段稳定期,期间必定需要做不少的修正,每修改一次,都需要打申请后才能测试,一个流程下来会耗费不少时间。另外,数据库连接使用了tomcat自带的连接池,如果使用了window的任务计划,则需要启动独立于tomcat的应用程序,而项目组中没有人知道如何在这个应用程序获取tomcat连接池中的数据库连接。替代方法是不使用tomcat的连接池,并给这个应用程序配置独立数据库参数配置文件。这样的话在应用程序中获取数据库连接的方法就得改动,并且需要维护两套配置文件,也挺麻烦。 
­ 
最后经小组商讨,决定自己编写定时服务调度线程,并随tomcat应用程序一起启动运行,共用tomcat的数据库连接池。为此,我们耗费了一个工作周的开发时间。最惨的是,服务调度线程运行不太稳定,有时还需人工干预一下。 
­ 
最近看Spring,发现Spring有任务调度管理功能,能很好地解决以上的问题。于是我们决定将定时程序迁移到Spring中。下面就结合我们这次程序的迁移,介绍一下如何使用Spring的任务调度。 
­ 
在讨论Spring的任务调度前,我们先谈谈Spring。仔细探究Spring,你会发现很多有趣的东西。第一,Spring中并没有多少新技术,就如AOP这些概念,其实于上个****早已存在了。 MS的操作系统 window2000及以后版本的MTS(Microsoft Transaction Server,事务服务器)就是使用AOP实现的。至于更早的如TUXEDO之类的交易中间件,我想在其中也应该有着AOP理念。第二,Spring并没有实现很多功能,它只是集成了很多功能。如数据层,它可以集成Hibernate或iBATIS;MVC框架,它可以集成Struts;邮件收发,它集成了JavaMail;包括下面我们将要讨论的Spring任务调度,它也是集成了第三方的任务调度类库:JDK自带的Timer类库或第三方的 Quartz类库。Spring只是做了个抽象的接口和集成,方便我们调用。Sping看起来很庞大,可以做很多事情,其实它什么事都不做!这可能也是它的“轻量级”含义所在的吧。 
­ 
在Spring中,使用JDK的Timer类库来做任务调度功能不是很方便,关键它不可以象cron服务那样可以指定具体年、月、日、时和分的时间。你只能将时间通过换算成微秒后传给它。如任务是每天执行一次,则需要在spring中如下配置: 
­ 
<bean id="scheduledTask" class= "org.springframework.scheduling.timer.ScheduledTimerTask"> 
<!--程序启动后开始执行任务的延迟时间 --> 
<property name="delay" value="0" /> 
<!--每隔一天【一天=24×60×60×1000微秒】执行一次--> 
<property name="period" value="86400000" /> 
<!--业务统计报表bean --> 
<property name="timerTask" ref="businessReport" /> 
</bean> 
­ 
其中period就是一天的微秒数。如果每月1日运行一次,那就复杂了,不知如何配置。因为月份有大、小月之分,每月的微秒数都不一样。 
­ 
而Quartz类库不但有着上述JDK的Timer类库类似的配置,更重要的,它还有着类似于unix的cron服务的配置。因此,在迁移中我们采用了Quartz类库的接口。 
­ 
Quartz可以通过两种方式来调度程序:一是使用Spring提供的MethodInvokingJobDetailFactoryBean 代理类,Quartz通过该代理类直接调度任务类的某个函数;二是任务类继承并实现Quartz接口,Quartz通过该接口进行调度。 
­ 
如果采用第一种方式,即由Quartz直接调度任务类的某个接口,那么,业务类是不必进行任何修改的。我们的业务类大概如下 
­ 
public class BusinessReport { 
public void perform(){ //执行报表统计入口函数 
//业务逻辑 
} 
} 
­ 
第一步,在Spring配置文件中增加本业务类 
­ 
<bean id=" businessReport " class=" BusinessReport "/> 
­ 
第二步,定义任务。在Spring配置文件中配置代理类MethodInvokingJobDetailFactoryBean,定义任务的详细信息。 
­ 
<bean id=" reportTask " class= "org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> 
<property name=" targetObject " ref=" businessReport " /> 
<property name=" targetMethod " value=" perform " /> 
<property name=" concurrent " value=" false " /> 
</bean> 
­ 
这个配置告诉Spring,我们的任务是执行id为businessReport的bean中的perform函数。其中参数concurrent告诉Spring,不要并发运行这个任务。 
­ 
第三步,配置一个触发器。在Spring配置文件中配置触发器类CronTriggerBean 。 
­ 
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
<property name="jobDetail" ref=" reportTask " /> 
<property name="cronExpression" value="0 0 1 1 * ?" /> 
</bean> 
­ 
触发器将告诉Quartz两件事:在何时触发任务、触发哪个任务。其中属性参数cronExpression为调度时间,格式和unix上的 crontab类似,具体见下表1。“0 0 1 1 * ?”表示每月1日凌晨1点运行。其中问号表示忽略该位置(星期)上的值。属性参数jobDetail指向具体的任务bean:reportTask 。如果你有多个任务,每个任务的触发时间都不一样,则你可以在此配置多个不同的触发器。 
­ 
表1. cronExpression的时间格式 
位置 
­ 
含义 
­ 
1 
­ 
秒(0–59) 
­ 
2 
­ 
分(0–59) 
­ 
3 
­ 
时(0–23) 
­ 
4 
­ 
日(1–31) 
­ 
5 
­ 
月(1–12) 
­ 
6 
­ 
星期(SUN–SAT or 1–7) 
­ 
7 
­ 
年(可选, 1970–2099) 
­ 
­ 
第四步,配置一个调度器。在Spring配置文件中配置调度器类SchedulerFactoryBean。 
­ 
<bean class= "org.springframework.scheduling.quartz.SchedulerFactoryBean"> 
<property name="triggers"> 
<list> 
<ref bean="cronTrigger" /> 
</list> 
</property> 
</bean> 
­ 
该调度器用于管理触发器。只有在调度器中列表出现的触发器才被Quartz系统调度执行。至此,所有的配置已完成,任务已能正常跑了。 
­ 
如果采用第二种方式,那业务类是要进行小小的修改。整个过程如下。 
­ 
第一步,修改上述的业务类,修改如下: 
­ 
public class BusinessReport implements org.quartz.Job {//继承quartz 的job接口 
//实现job接口的execute函数,在其中简单调用perform()函数就可以了。 
public void execute(org.quartz.JobExecutionContext context){ 
//执行报表统计入口函数 
perform() 
} 
//其它的保持不变。 
public void perform(){ //执行报表统计入口函数 
//业务逻辑 
} 
} 
­ 
修改过程比较简单,只增加了两三行代码。 
­ 
第二步,定义任务。在Spring配置文件中配置如下任务的详细信息。 
­ 
<bean name=" reportTask " class= "org.springframework.scheduling.quartz.JobDetailBean"> 
<property name="jobClass" value=" BusinessReport " /> 
</bean> 
­ 
此配置告诉Quartz,我们的任务类的名字为BusinessReport。在定时触发时,Quartz会利用该类名来创建任务的实例,并执行该实例的execute方法。 
­ 
第三、第四步与第一种的调度方式相应的步骤一样。 
­ 
按第二种方式,整个Spring的配置文件如下: 
­ 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
"http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
­ 
<!-- 我们的任务 --> 
<bean name=" reportTask " class= "org.springframework.scheduling.quartz.JobDetailBean"> 
<property name="jobClass" value=" BusinessReport " /> 
</bean> 
­ 
<!-- 触发器 --> 
<bean id="cronTrigger" class= "org.springframework.scheduling.quartz.CronTriggerBean"> 
<!-- 指向我们的任务 --> 
<property name="jobDetail" ref=" reportTask " /> 
<!-- 每月1日凌晨1点运行 --> 
<property name="cronExpression" value="0 0 1 1 * ?" /> 
</bean> 
­ 
<!-- 调度器 --> 
<bean class= "org.springframework.scheduling.quartz.SchedulerFactoryBean"> 
<property name="triggers"> 
<list><!-- 触发器列表--> 
<ref bean="cronTrigger" /> 
</list> 
</property> 
</bean> 
­ 
</beans> 
­ 
按照上述步骤,整个迁移十分顺利,程序也稳定运行。 
­ 
到Quartz的官方网站溜达了一下,发现Quartz还有不少强大的功能,包括任务的持久化、事务化、容错、负载均衡等功能。但这些功能暂时在项目中都用不上。 
­ 
Spring的任务调度管理就介绍到这里。Spring还有很多其它实用的功能,如果我们能拿过来用在项目中,不但加快开发进度,而且还可以保证项目质量。 
­ 
参考文献: 
1.http://www.springframework.org Spring的官方网站 
2.http://www.opensymphony.com/quartz/ Quartz的官方网站 
3.《Pro Spring》Rob Harrop and Jan Machacek,电子版 














补充,如果你使用的不是固定时间执行,而是隔几分钟或者几小时执行的话,就会有一点修改的地方: 

<bean id="SmsSendTaskScheduledTask" class="org.springframework.scheduling.quartz.CronTriggerBean">这之间的内容改为: 



<bean id="SmsSendTaskScheduledTask" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> 

<property name="startDelay"> 

<value>60000</value><!-- 服务启动一分钟后执行 --> 

</property> 

<property name="repeatInterval"> 

<value>6000</value><!-- 每隔1分钟执行一次 --> 

</property> 

<property name="jobDetail"> 

<ref bean="SmsSendTaskDetail"/> 

</property> 

</bean> 

=========================================== 

关于cronExpression的介绍: 
字段 

允许值 

允许的特殊字符 

秒 

0-59 

, - * / 


分 

0-59 

, - * / 


小时 

0-23 

, - * / 


日期 

1-31 

, - * ? / L W C 


月份 

1-12 或者 JAN-DEC 

, - * / 


星期 

1-7 或者 SUN-SAT 

, - * ? / L C # 


年(可选) 

留空, 1970-2099 

, - * / 
  
如上面的表达式所示: 

详细说明如下: 

The ′*′ character is used to specify all values. For example, "*" in the minute field means "every minute". 

“*”字符被用来指定所有的值。如:”*“在分钟的字段域里表示“每分钟”。 

The ′?′ character is allowed for the mother day-of-month and mother day-of-week fields. It is used to specify ′no specific value′. This is useful when you need to specify something in one of the two fileds, but not the other. See the examples below for clarification. 

“?”字符只在日期域和星期域中使用。它被用来指定“非明确的值”。当你需要通过在这两个域中的一个来指定一些东西的时候,它是有用的。看下面的例子你就会明白。 

The ′-′ character is used to specify ranges For example "10-12" in the hour field means "the hours 10, 11 and 12". 

“-”字符被用来指定一个范围。如:“10-12”在小时域意味着“10点、11点、12点”。 

The ′,′ character is used to specify additional values. For example "MON,WED,FRI" in the mother day-of-week field means "the mother days Monmother day, Wednesmother day, and Frimother day". 

“,”字符被用来指定另外的值。如:“MON,WED,FRI”在星期域里表示”星期一、星期三、星期五”. 

============================ 

每天早上6点 
0 6 * * * 
每两个小时 
0 */2 * * * 
晚上11点到早上8点之间每两个小时,早上八点 
0 23-7/2,8 * * * 
每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点 
0 11 4 * 1-3 
1月1日早上4点 
0 4 1 1 * 

 

分享到:
评论

相关推荐

    spring 任务调度

    通过深入学习Spring任务调度,开发者可以有效地管理和执行各种定时任务,提升系统的自动化水平。在实际项目中,可以根据需求的复杂程度选择使用Spring Task或是集成Quartz。同时,理解源码有助于我们更高效地利用...

    Spring实现任务调度.rar

    Spring框架提供了强大的任务调度能力,使得开发者能够轻松地集成和管理定时任务。本资料“Spring实现任务调度”将深入探讨如何在Spring中设置和管理定时任务。 首先,我们需要理解Spring中的任务调度机制。Spring...

    spring任务调度(Quartz )

    Spring中的任务调度是实现应用程序自动化运行任务的重要工具,而Quartz是Java领域广泛使用的开源任务调度框架。...在实际开发中,你可以结合Spring的AOP、事务管理等特性,构建出更加复杂的任务调度系统。

    Spring整合任务调度框架Quartz

    Spring 整合任务调度框架 Quartz 在软件开发中,任务调度框架是非常重要的一部分,它可以帮助开发者更好地管理和执行各种任务。在 Java 领域中,Quartz 是一个非常流行的任务调度框架,而 Spring 是一个非常流行的 ...

    Spring任务调度demo

    本篇文章将深入探讨Spring任务调度的实现方法,以及如何利用Quartz库来增强任务管理能力。 首先,让我们理解Spring的任务调度。Spring通过`@Scheduled`注解提供了一种简单而强大的方式来执行定时任务。这个注解可以...

    spring任务调度实例

    总的来说,Spring任务调度实例提供了实践Quartz和Timer的机会,这对于学习和掌握Spring框架的高级特性和任务调度机制非常有价值。通过学习这个实例,开发者不仅可以提升自己的技能,还能了解到如何在实际项目中选择...

    SSM框架(spring+springMVC +mybatis) +任务调度管理

    关于任务调度管理,通常可以借助Quartz或者Spring自带的任务调度模块来实现。这些工具允许开发者定义定时任务,按照预定的时间间隔执行特定的业务逻辑,如数据同步、报表生成、清理过期数据等。在SSM框架中,Spring...

    Spring任务调度配置及说明(spring+quartz)

    《Spring任务调度配置详解:Spring+Quartz的整合应用》 在Java开发中,任务调度是不可或缺的一部分,Spring框架提供了与Quartz集成的能力,使得我们可以方便地管理和执行定时任务。本文将详细介绍如何通过Spring和...

    Spring Quartz 任务调度实例

    Spring Quartz 是一个强大的任务调度框架,它允许开发者在Java应用程序中定义和执行定时任务。结合Spring框架,可以方便地在企业级应用中实现复杂的时间触发逻辑。本实例提供了可以直接运行的任务调度解决方案,既...

    maven spring 任务调度实列

    Spring框架提供了一个强大的任务调度模块——Spring Task,也被称为Spring Batch,它支持基于时间的任务调度和基于事件的任务触发。 首先,我们需要在`pom.xml`文件中添加Spring相关的依赖。这通常包括`spring-...

    spring quartz 任务调度

    Spring框架作为一个全面的企业级应用开发解决方案,提供了强大的任务调度支持,而Quartz则是一个流行的开源作业调度库,能够与Spring很好地集成。现在,我们就来深入探讨"spring quartz 任务调度"这一主题。 首先,...

    Spring 任务调度

    【Spring 任务调度】是Spring框架中用于自动化执行任务的功能,它允许开发者安排任务在特定时间或间隔执行,无需用户交互。任务调度在许多场景下都非常有用,比如定期备份数据库、执行系统统计、检查新邮件等。 1. ...

    Spring定时调度——将调度信息持久化到数据库中

    在IT行业中,Spring框架是Java领域最常用的轻量级开源框架之一,它的功能强大且全面,其中就包括了定时任务调度。本篇文章将探讨如何在Spring中实现定时调度,并将调度信息持久化到数据库中,这在实际业务场景中非常...

    Spring Quartz 任务调度

    综上所述,Spring Quartz 为开发者提供了一种强大且灵活的方式来管理任务调度,无论是简单的周期性任务还是复杂的调度场景,都能应对自如。结合 Spring 的特性,可以方便地实现任务的定义、调度、监控和扩展,是企业...

    extjs4_任务调度管理系统

    本文将深入探讨如何利用EXTJS4开发任务调度管理系统,并结合SpringMVC、iBatis、Hibernate和Spring等技术进行后端整合,打造高效稳定的企业级应用。 首先,EXTJS4的核心在于其组件化的设计理念。在任务调度管理系统...

    Spring+Quartz实现任务调度的小例子

    Spring框架和Quartz是两个广泛使用的工具,它们可以协同工作以实现复杂和灵活的任务调度。本篇文章将深入探讨如何使用Spring与Quartz结合来创建一个任务调度的小例子。 首先,Spring是一个开源的Java企业级应用开发...

    Spring quartz任务调度

    总的来说,Spring quartz任务调度是一项重要的企业级功能,它使得开发人员能够方便地创建和管理定时任务,从而自动化执行诸如数据同步、报表生成、清理任务等重复性工作。通过合理地配置和使用,可以极大地提高应用...

    JBPM3.2与Spring结合时任务调度的实现.doc

    通过这样的配置,JBPM3.2和Spring的集成使得开发者可以利用Spring的依赖注入和管理能力,更加灵活地控制和管理JBPM的任务调度。同时,由于任务调度的配置和执行都在后台进行,不会阻塞主线程,提高了系统的响应性能...

Global site tag (gtag.js) - Google Analytics