定时任务—Spring中集成Quartz

    Java的定时任务实现有三种,一种是使用JDK自带的Timer那个类来实现,另一种是使用quartz框架来实现,最后一种是在项目使用Spring框架的情况下用Spring框架来实现。JDK自带的类是单线程的,而且只能定义特定时间去执行任务,而不能指定任务执行的频率,所以一般用的较少,只有处理一些简单的程序才会用到。而quartz是一个轻量级的框架,支持多线程,支持定义频率,所以非常方便。我目前用的是SSM框架,所以就用quartz来实现了。

    Quartz是一个开源项目,它可以与j2EE和j2SE结合使用,也可以单独使用。Quartz可以用来创建许多Jobs这样的复杂的程序,并通过cron表达式自定义执行的规则。

本篇是配置的单机的,分布式的情况请参看基于spring+quartz的分布式定时任务框架

 

Quartz的几个核心概念

Job:是一个接口,此接口只有一个方法execute(JobExecutionContext context),开发者通过实现该接口来定义需要执行的任务,Job运行时的信息保存在JobDataMap实例中。JobExecutionContext类提供了调度上下文的各种信息。

JobDetailQuartz在每次执行Job时,都重新创建一个Job实例,所以它不是直接接收一个Job实例,而是接收一个Job实现类,以便通过反射机制实例化Job,因此需要一个类来描述Job的实现类及其相关的静态信息(Job名称、描述等),JobDetail承担了这一角色。

Trigger:一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或以固定间隔周期性执行时,可以使用SimpleTrigger。当需要复杂的调度方案,可以使用CronTrigger(通过Cron表达式定义出各种复杂时间规则的调度方案)。

Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,二者在Scheduler中拥有各自的组和名称,可以注册多个JobDetial和Trigger。组及名称是Scheduler查找定位容器中某一对象的依据,因此,组及名称必须唯一,但是Trigger和JobDetail的组和名称可以相同,因为它们是不同的类型。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。

SchedulerFactory:代表一个调度工厂,用来创建一个scheduler调度器。

    Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例。
 

下面这段了解即可:

    Job有一个StatefulJob子接口,代表有状态的任务。它是一个没有方法的标签接口,目的是让Quartz知道任务的类型,以便执行不同的方案。无状态任务在执行时拥有自己的JobDataMap复制,对JobDataMap的更改不会影响下次的执行。而有状态任务共享同一个JobDataMap实例,每次执行任务对JobDataMap的更改会保存下来,会对后面的执行产生影响。因此,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行。如果前次的StatefulJob还没有执行完毕,则下次的任务将阻塞等待,直到前次任务执行完毕。避免使用有状态的Job。使用数据库持久化任务调度信息,则无状态的JobDataMap仅在Scheduler注册任务时保存一次,而有状态的任务的JobDataMap在每次执行任务后都会进行保存。
 

 

 

CRON表达式

CRON表达式用来自定义Quartz执行规则,在实际使用时可以借助在线自动生成工具:http://cron.qqe2.com/,所以下面的具体规则大致了解即可:

①CRON由7个组成:秒 分 时 日 月 周 年 ,以空格作为分界。

②特殊字符:*(星号)    ?(问号)     ,(逗号)    /(斜杠)    -(中划线)    L    W    #(井号)

    ■ *(星号)指示着你想在这个域上包含所有合法的值。例如,在月份域上使用星号意味着每个月都会触发这个 trigger。

    ■ ?(问号)只能用在日和周域上,但是不能在这两个域上同时使用指不为该域指定值

    ■ ,(逗号)是用来在给某个域上指定一个值列表的。例如,使用值 0,15,30,45在秒域上意味着每15秒触发一个 trigger。 

    ■ /(斜杠)用于时间表的递增的。例如 0/15表示每15分钟的递增。

    ■ -(中划线)用于指定一个范围。例如,在小时域上的 3-8意味着 "3,4,5,6,7和 8 点

    ■ 代表某域上允许的最后一个值。用在日表示一个月中的最后一天,用在周表示该月最后一个星期X。它仅被日和周域支持

    ■ 代表离给定日期最近的工作日,并且仅能用于日域中

    ■ #(井号) 字符仅能用于周域中。它用于指定月份中的第几周的哪一天。表示该月第几个周X。6#3表示该月第3个周五。

详情参考:SpringQuartz定时任务的cron表达式书写

 

 

在Spring配置使用Quartz流程详解

① 导入相关依赖,这里我是用Maven管理jar包的(注意spring3.1及以上版本支持quartz2)!

了解最新的可以去官网:http://www.quartz-scheduler.org/downloads/

在pom.xml中添加如下,之后记得import changes下:

  <dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
  </dependency>
  <dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.2.1</version>
  </dependency> 

 

② spring配置文件中的基本配置 (applicationContext.xml)

● xmlns和 xsi:schemaLocation配置

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    ...
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="...   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">
...
</beans>

● task任务扫描注解   

<!-- 加载定时任务 -->
<task:annotation-driven/>

●扫描的位置       

<!-- 自动扫描 -->
<context:component-scan base-package="cn.xx55xx.quartz"/>

 

③ spring配置文件中的任务相关配置

<!--线程执行器配置,用于任务注册-->
<bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
	<property name="corePoolSize" value="10" />
	<property name="maxPoolSize" value="100" />
	<property name="queueCapacity" value="500" />
</bean>

<!-- Quartz  Job 业务对象-->
<bean id="orderPayStatusJob" class="cn.xx55xx.quartz.OrderPayStatusJob"></bean>

<!-- Quartz  JobDetail 调度业务-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	<property name="targetObject" ref="orderPayStatusJob"/>
	<property name="targetMethod" value="updateStatus" />
</bean>

<!-- Quartz CronTrigger 增加调用的触发器,触发时间 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
	<property name="jobDetail" ref="jobDetail"/>
	<property name="cronExpression" value="0/5 * * * * ?" /> <!-- 每5秒触发一次 -->
    <!--<property name="cronExpression" value="0 0/5 * * * ?" />  --> <!-- 每5min触发一次 -->
</bean>

<!-- Quartz  设置调度 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="triggers">
		<list>
			<ref bean="cronTrigger" />
		</list>
	</property>
	<property name="taskExecutor" ref="executor" />
</bean>

 

④根据需要在类中写好自己业务逻辑代码

package cn.xx55xx.quartz;

import java.text.SimpleDateFormat;
import java.util.Date;

public class OrderPayStatusJob {

    /**
     * 业务逻辑处理
     *
      */
    private static int count = 0;
    public void updateStatus() {
        System.out.println(count++);
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); //打印当前时间
    }
}

 

回想一下之前说过的Quartz三个要素:Scheduler、Trigger、JobDetai&Job。对应到xml文件,也就是上面的中的几个bean对象。几个点注意下:

一个scheduler可以对应多个Trigger:看bean对象也看出来了,它的属性是个list集合。

一个job可以对应多个JobDetail:这个其实也好理解,毕竟具体的实现是job实现,但是通过jobDetail去管理job。

job可以自己指定方法名: 之前job都是通过实现job接口,实现execute方法。现在只需要通过jobDetai的属性targetMethod指定执行方法,但是需要注意这个jobDetail它是使用MethodInvokingJobDetailFactoryBean作为具体实现。
 

 

补充几个CRON表达式例子:

 每隔5秒执行一次:*/5 * * * * ?

 每隔1分钟执行一次:0 */1 * * * ?

 每天23点执行一次:0 0 23 * * ?

 每天凌晨1点执行一次:0 0 1 * * ?

 每月1号凌晨1点执行一次:0 0 1 1 * ?

 每月最后一天23点执行一次:0 0 23 L * ?

 每周星期天凌晨1点实行一次:0 0 1 ? * L

 在26分、29分、33分执行一次:0 26,29,33 * * * ?

 每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值