您的位置:首页 > 编程语言 > Java开发

Spring+Quartz整合,实现定时任务

2017-07-17 00:00 519 查看

Quartz

Quartz是一个开源的定时任务框架,在一些日常的任务中,我们经常有一些这样的需要,比如 每天、每周或每月生成相应的业务报表;每天统计系统注册人数;定期清理平台长久不登录的用户等等。 如果遇到这种业务场景却要让人定时去操作统计,那费时又费力! 此时,Quartz这个框架就能帮我们不少忙了。

Spring整合Quartz实现定时任务步骤很简单,大致需要经过如下几步:

创建任务(Job)、

配置JobDetail、

配置触发器(Trigger)、

配置SchedulerFactoryBean

首先使用Maven创建一个web项目并引入Spring和quartz的依赖

使用的版本Spring4.3.9+Quartz2.3.0

Maven的pom.xml的配置:

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.9.RELEASE</spring.version>
</properties>

<!-- spring 环境 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- Quartz 定时器框架 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>


增加完Spring和Quartz的依赖包之后,就需要创建Spring配置文件,并在web.xml文件中引入Spring支持。

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>


到现在为止,基本的环境算是搭建好了,接下来我们就要开始Spring+Quartz实现定时任务了

一、创建任务(Job)

Spring+Quartz实现Job有两种方式:

①继承org.springframework.scheduling.quartz.QuartzJobBean类来实现Job任务,并实现里面的抽象方法executeInternal;

②是不继承任何类,创建普通的Java类,然后自己指定任务的执行方法(显然,第②种方式更加灵活,实现起来方便而且大大降低了系统的业务的耦合性)。

———————————————————————————————————————————

我们先来看一下继承QuartzJobBean类的这种形式,创建一个任务类SpringQtz1,具体代码如下:

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

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class SpringQtz1 extends QuartzJobBean {
private static int counter = 0;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println("(" + counter++ + ")"+ "\t" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

}

}


为了演示方便,executeInternal方法中没有写复杂的业务逻辑,只简单的输出2行信息,真正的生产环境中在该方法中实现你所需要的业务逻辑即可。 ヾ(๑╹◡╹)ノ"

二、在Spring配置文件中配置JobDetail

<!--方式①:使用JobDetailBean,任务类必须实现Job接口 -->
<bean  id="exampleJobDetail"  class="org.springframework.scheduling.quartz.JobDetailFactoryBean ">
<property name="jobClass" value="com.dayuanit.functionTest.SpringQtz1"></property>
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="5" />
</map>
</property>
</bean>


三、配置触发器(Trigger)

org.springframework.scheduling.quartz.SimpleTriggerFactoryBean(此种方式是很隔多长时间进行触发一次,比如每隔24小时触发一次)

org.springframework.scheduling.quartz.CronTriggerFactoryBean(此种方式是在指定的时间进行触发,比如只在周一进行触发。不过根据配置也很方便的实现类似SimpleTriggerFactoryBean形式的定时任务)

Spring所提供的这两种触发器方式和前面提到的任务创建方式均可以相互之间混用,很灵活。

这里我们先使用SimpleTriggerFactoryBean这个trigger来配置 (๑¯∀¯๑)

<!-- ======================== 调度触发器 ========================  -->
<bean id="exampleJobTrigger"  class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="exampleJobDetail" />
<!-- 延迟触发时间,延迟10秒进行触发 -->
<property name="startDelay" value="10000" />
<!-- 重复触发的时间间隔,5秒 -->
<property name="repeatInterval" value="5000" />
</bean>


四、配置SchedulerFactoryBean

<!-- ======================== 调度工厂 ========================  -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="exampleJobTrigger" />
</list>
</property>
</bean>


启动Tomcat,运行结果如下:

(0)	2017-07-17 20:10:55
(1)	2017-07-17 20:11:00
(2)	2017-07-17 20:11:05
(3)	2017-07-17 20:11:10
(4)	2017-07-17 20:11:15
(5)	2017-07-17 20:11:20
(6)	2017-07-17 20:11:25
(7)	2017-07-17 20:11:30
(8)	2017-07-17 20:11:35
(9)	2017-07-17 20:11:40

———————————————————————————————————————————

注意:如果出现

异常信息。 是因为Quartz从1.X升级到2.X之后,JobDetail由类修改为接口了 。

将配置JobDetail的文件路径,由org.springframework.scheduling.quartz.JobDetailBean

改成 org.springframework.scheduling.quartz.JobDetailFactoryBean 即可。

为了确保万无一失,大家可以在改后,按住Ctrl键+鼠标光标移动到相应的配置路径上,看路径是否能变成一个超链接,如果能顺利变成一个超链接的话,说明配置无误;反之无任何反应,则需要更改!٩(๑`^´๑)۶

———————————————————————————————————————————

第②种 不继承任何类,创建普通的Java类,在配置文件里定义任务类和要执行的方法,类和方法仍然是普通类。(推荐使用的方式)

首先创建一个基本的Java类来做为Job任务类,代码如下:

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

public class SpringQtz2 {
private static int counter = 0;
protected void execute()  {
System.out.println("(" + counter++ + ")"+ "\t" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}


接下来是在Spring配置文件中配置JobDetail、Trigger、SchedulerFactoryBean

<!-- 方法②:使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法-->
<!-- 定义目标bean和bean中的方法 -->
<bean id="SpringQtz2" class="com.dayuanit.functionTest.SpringQtz2"/>
<bean id="SpringQtzJobMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 指定任务类 -->
<property name="targetObject">
<ref bean="SpringQtz2"/>
</property>
<!-- 指定任务的执行方法 -->
<property name="targetMethod">
<value>execute</value> <!-- 要执行的方法名称 -->
</property>
</bean>

<!--======================== 调度触发器 ========================  -->
<bean id="CronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="SpringQtzJobMethod"></property>
<!-- 每5秒运行一次 -->
<property name="cronExpression" value="0/5 * * * * ?"></property>
</bean>

<!--======================== 调度工厂 ========================  -->
<bean id="SpringJobSchedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="CronTriggerBean"/>
</list>
</property>
</bean>

配置完之后我们再启动一下程序,看看定时任务时否运行良好 (≖ᴗ≖)✧
(这里我们使用的Trigger是CronTriggerFactoryBean,当然也可以使用SimpleTriggerFactoryBean)

关于Trigger中时间如何配置,quartz官网描述的很清楚,大家可以参考如下网址:
http://quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/crontrigger

还是搬点中文 Cron表达式 说明过来吧 ─=≡Σ((( つ•̀ω•́)つ

使用CronTrigger主要的是要掌握Cron表达式。Cron表达式包含6个必要组件和一个可选组件,如下表所示。

位置 含义 允许的特殊字符
1 秒(0~59)
, - * /
2 分(0~59)
, - * /
3 小时(0~24)
, - * /
4 日期(1~31)
, - * / ? L W C
5 月(JAN~DEC或1~12)
, - * /
6 星期(SUN~SAT或1~7) , - * / ? L C #
7 年(可选,1970~2099),若为空,表示全部时间范围 , - * /
特殊字符的含义,见下表。

特殊字符 说明
* 通配符,任意值
? 无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查
- 范围。e.g.小时部分10-12表示10:00,11:00, 12:00
, 列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON、TUE和WED
/ 增量。表示一个值的增量,e.g.分钟域中0/1表示从0开始,每次增加1min
L 表示Last。它在日期和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中,它永远是7(星期六)。当你希望使用星期中某一天时,L字符非常有用。e.g.星期域中6L表示每一个月的最后一个星期五
W 在本月内离当天最近的工作日触发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离是0;所谓本月内指的是不能跨月取到最近工作日,即使前/后月份的最后一天/第一天确实满足最近工作日。e.g. LW表示本月的最后一个工作日触发,W强烈依赖月份。
# 表示该月的第几个星期,e.g. 1#2表示每一个月的第一个星期一
C 日历值。日期值是根据一个给定的日历计算出来的。在日期域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。例如在一个星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五)
Cron表达式举例:

"30 * * * * ?" 每半分钟触发任务

"30 10 * * * ?" 每小时的10分30秒触发任务

"30 10 1 * * ?" 每天1点10分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秒内,每秒都触发任务

"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秒触发任务
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: