Spring 3整合Quartz实现定时任务

  1. Quartz介绍
  2. Quartz中的概念
  3. Spring 中使用 Quartz
    1. 所需 jar 包
    2. 添加业务逻辑类
    3. 配置文件
      1. SimpleTrigger 方式
      2. CronTrigger 方式
  4. Cron表达式
    1. 例子
  5. 动态配置定时任务

Quartz介绍

在企业应用中,我们经常会碰到时间任务调度的需求,比如每天凌晨生成前天报表,每小时生成一次汇总数据等等。Quartz 是出了名的任务调度框架,它可以与 J2SEJ2EE 应用程序相结合,功能灰常强大,轻轻松松就能与 Spring 集成,使用方便。

spring3.1 以下的版本必须使用 quartz1.x 系列,3.1 以上的版本才支持 quartz 2.x,不然会出错。

Quartz中的概念

主要有三个核心概念:调度器、任务和触发器。三者关系简单来说就是,调度器负责调度各个任务,到了某个时刻或者过了一定时间,触发器触动了,特定任务便启动执行。概念相对应的类和接口有:

  1. JobDetail:望文生义就是描述任务的相关情况;

  2. Trigger:描述出发Job执行的时间触发规则。有 SimpleTriggerCronTrigger 两个子类代表两种方式,一种是每隔多少分钟小时执行,则用 SimpleTrigger;另一种是日历相关的重复时间间隔,如每天凌晨,每周星期一运行的话,通过 Cron 表达式便可定义出复杂的调度方案。

  3. Scheduler:代表一个 Quartz 的独立运行容器,TriggerJobDetail 要注册到 Scheduler 中才会生效,也就是让调度器知道有哪些触发器和任务,才能进行按规则进行调度任务。

Spring 中使用 Quartz

所需 jar 包

quartz.jar,spring-context-support.jar,commons-collections-3.2.jar;

添加业务逻辑类

简单示例:

public class QuartzTest {

    //到了某个时刻就会被调用
    public void autoRun(){
        System.out.println("It's time to run :" + new Date().toString());
        //TODO 执行任务逻辑
        //........
    }
}

配置文件

SimpleTrigger 方式

    <!-- Quartz -->
    <bean name="quartzTest" class="com.jz.schedual.QuartzTest" />
    <bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="quartzTest"></property>
        <property name="targetMethod" value="autoRun"></property>
        <property name="concurrent" value="false"></property><!-- 作业不并发调度,表示等上一个任务执行完后再开启新的任务 -->
    </bean>

    <bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
        <property name="jobDetail" ref="quartzTestJob"/>
        <!-- 调度工厂实例化后,经过20秒开始执行调度(即tomcat启动后多久启动定时器) -->
        <property name="startDelay" value="20000" />
        <!-- 每隔多长时间(毫秒)执行一次 ,30秒-->
        <property name="repeatInterval" value="30000" />
    </bean>

    <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref local="quartzTestTrigger" />
            </list>
        </property>
    </bean>

CronTrigger 方式

    <!-- Quartz -->
    <bean name="quartzTest" class="com.jz.schedual.QuartzTest" />
    <bean id="quartzTestJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="quartzTest"></property>
        <property name="targetMethod" value="autoRun"></property>
        <property name="concurrent" value="false"></property>
    </bean>

    <bean id="quartzTestTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="quartzTestJob"/>
        <!-- 每天十点 -->
        <property name="cronExpression" value="0 0 10 * * ?"></property>
    </bean>

    <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref local="quartzTestTrigger" />
            </list>
        </property>
    </bean>

Cron表达式

cronExpression 定义时间规则,Cron 表达式由6或7个空格分隔的时间字段组成: 分钟 小时 日期 月份 星期 (可选);

字段 允许值 允许的特殊字符
0-59 , - * /
0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 , - * /
星期 1-7 , - * ? / L C #
1970-2099 , - * /

解析: 每 5 秒执行一次

0/5 * * * * ?
  1. *”字符被用来指定所有的值
    如:"*"在分钟的字段域里表示“每分钟”。

  2. ?”字符只在日期域星期域中使用。它被用来指定“非明确的值”。当你需要通过在这两个域中的一个来指定一些东西的时候,它是有用的。看下面的例子你就会明白。月份中的日期和星期中的日期这两个元素时互斥的一起应该通过设置一个问号来表明不想设置那个字段

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

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

  5. /”字符用于指定增量
    如:“0/15”在秒域意思是每分钟的0,15,30和45秒
    5/15”在分钟域表示每小时的5,20,35和50
    符号“*”在“/”前面(如:*/10)等价于0在“/”前面(如:0/10)。
    记住一条本质:表达式的每个数值域都是一个有最大值和最小值的集合,如: 秒域和分钟域的集合是 0-59,日期域是 1-31,月份域是 1-12。字符“/”可以帮助你在每个字符域中取相应的数值
    如:“7/6”在月份域的时候只 有当7月的时候才会触发,并不是表示每个6月。

  6. L 是“last”的省略写法可以表示 day-of-monthday-of-week 域,但在两个字段中的意思不同,例如 day-of- month 域中表示一个月的最后一天。如果在 day-of-week 域表示“7”或者“SAT
    如果在 day-of-week 域中前面加上数字,它表示一个月的最后几天,例如“6L”就表示一个月的最后一个星期五。

  7. 字符“W”只允许日期域出现。这个字符用于指定日期的最近工作日
    例如:如果你在日期域中写 “15W”,表示:这个月15号最近的工作日。所以,如果15号是周六,则任务会在14号触发。如果15好是周日,则任务会在周一也就是16号触发。如果 是在日期域填写“1W”即使1号是周六,那么任务也只会在下周一,也就是3号触发,“W”字符指定的最近工作日是不能够跨月份的。字符“W”只能配合一个 单独的数值使用,不能够是一个数字段,如:1-15W是错误的。

  8. L”和“W”可以在日期域中联合使用,LW表示这个月最后一周的工作日

  9. 字符“#”只允许在星期域中出现。这个字符用于指定本月的某某天
    例如:

    • 6#3”表示本月第三周的星期五(6表示星期五,3表示第三周)。
    • 2#1”表示本月第一周的星期一
    • 4#5”表示第五周的星期三
  10. 字符“C”允许在日期域星期域出现。这个字符依靠一个指定的“日历”。也就是说这个表达式的值依赖于相关的“日历”的计算结果,如果没有“日历” 关联,则等价于所有包含的“日历”。
    如:日期域是“5C”表示关联“日历”中第一天,或者这个月开始的第一天的后5天。星期域是“1C”表示关联“日历” 中第一天,或者星期的第一天的后1天,也就是周日的后一天(周一)。

例子

字段 允许值
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 12 ? * WED 表示每个星期三中午12点
"0 0 12 * * ?" 每天中午12点触发
"0 15 10 ? * *" 每天上午10:15触发
"0 15 10 * * ?" 每天上午10:15触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
"0 15 10 15 * ?" 每月15日上午10:15触发
"0 15 10 L * ?" 每月最后一日的上午10:15触发
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
"30 * * * * ?" 每半分钟触发任务
"30 10 1 20 * ?" 每月20号1点10分30秒触发任务
"30 10 1 20 10 ? *" 每年10月20号1点10分30秒触发任务
"30 10 1 20 10 ? 2011" 2011年10月20号1点10分30秒触发任务
"30 10 1 ? 10 * 2011" 2011年10月每天1点10分30秒触发任务
"30 10 1 ? 10 SUN 2011" 2011年10月每周日1点10分30秒触发任务
"15,30,45 * * * * ?" 每15秒,30秒,45秒时触发任务
"15-45 * * * * ?" 15到45秒内,每秒都触发任务
0 * * * * ? * 每分钟触发一次
"15/5 * * * * ?" 每分钟的每15秒开始触发,每隔5秒触发一次
"15-30/5 * * * * ?" 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
"0 0/3 * * * ?" 每小时的第0分0秒开始,每三分钟触发一次
"0 15 10 ? * MON-FRI" 星期一到星期五的10点15分0秒触发任务
"0 15 10 L * ?" 每个月最后一天的10点15分0秒触发任务
"0 15 10 LW * ?" 每个月最后一个工作日的10点15分0秒触发任务
"0 15 10 ? * 5L" 每个月最后一个星期四的10点15分0秒触发任务
"0 15 10 ? * 5#3" 每个月第三周的星期四的10点15分0秒触发任务

动态配置定时任务

有时,我们会碰到这样的问题:需要修改触发器的触发时间,那么就要修改spring配置文件,再重启服务器,但是有很多时候我们没有条件去重启服务器;或者,有特定的需求,需要前台直接修改调度时间。这时候我们就要动态设置触发时间。详细配置请参考文章:http://ithead.iteye.com/blog/1460748

最后说一下,我们可以通过Quartz完整下载包中的Examples来快速学习使用掌握Quartz。

  1. http://www.cnblogs.com/jianzhi/p/3384436.html
  2. http://www.dexcoder.com/selfly/article/297
  3. 本文是系列《Spring Quartz 定时任务系列》中的其中一篇,点此查看本系列全部文章
  4. http://quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/crontrigger

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:Spring 3整合Quartz实现定时任务

文章字数:2.8k

本文作者:Bin

发布时间:2016-03-10, 23:05:05

最后更新:2019-08-21, 14:18:52

原始链接:http://coolview.github.io/2016/03/10/Spring/Spring-3%E6%95%B4%E5%90%88Quartz%E5%AE%9E%E7%8E%B0%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录