Spring3.0与Quartz的整合实现定时任务调度

时间:2022-02-07 07:49:30

 1.Maven项目,pom文件配置 

quartz-1.8.5.jar 
commons-logging.jar 
spring-core-3.0.5.RELEASE.jar 
spring-beans-3.0.5.RELEASE.jar 
spring-context-3.0.5.RELEASE.jar 
spring-context-support-3.0.5.RELEASE.jar 
spring-asm-3.0.5.RELEASE.jar 
spring-expression-3.0.5.RELEASE.jar 
spring.transaction-3.0.5.RELEASE.jar 
spring-web-3.0.5.RELEASE.jar
 

Maven的pom.xml的配置: 

<?xml version="1.0" encoding="UTF-8"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>QtzTest</groupId>
<artifactId>QtzTest</artifactId>
<version>1.0</version>

<properties>
<springframework.version>3.0.5.RELEASE</springframework.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${springframework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework.version}</version>
</dependency>

<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>1.8.5</version>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.5.4.v20111024</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
<contextPath>/${project.artifactId}</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
</project>
  特别注意一点,与Spring整合必须使用Quartz1.8.5及以下版本,最初我拿2.1.3的,怎么搞都报错:  
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.scheduling.quartz.CronTriggerBean] for bean with name 'mytrigger' defined in class path resource [applicationContext.xml]: problem with class file or dependent class; nested exception is java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class 

查看发现spring3.0.5中org.springframework.scheduling.quartz.CronTriggerBean继承了org.quartz.CronTrigger(public class CronTriggerBeanextends CronTrigger),而在quartz2.1.3中org.quartz.CronTrigger是个接口(publicabstract interface CronTrigger extends Trigger),而在quartz1.8.5及1.8.4中org.quartz.CronTrigger是个类(publicclass CronTrigger extends Trigger),从而造成无法在applicationContext中配置触发器。这是spring3和quartz2版本不兼容的一个bug。

 2.Spring配置文件

applicationContext.xml,可以定义一个或者多个定时任务

<!-- 定时任务 start -->
<!-- 定义目标bean和bean中的方法 -->
<bean id="testij" class="com.wlyd.wms.service.timer.TestijInfoJob"></bean>
<bean id="testTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="testij" /></property>
<property name="targetMethod"><value>execute</value></property> <!-- 要执行的方法名称 -->
</bean>
<bean id="test2" class="com.wlyd.wms.service.timer.Test2InfoJob"></bean>
<bean id="testTask2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="test2" /></property> <!-- 第2个定时任务的目标类 -->
<property name="targetMethod"><value>execute2</value></property> <!-- 第2个定时任务的方法 -->
</bean>
<!-- 调度触发器 -->
<bean id="testTime" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail"> <ref bean="testTask"/> </property>
<property name="cronExpression"> <value>* */5 * * * 1_7</value> </property>
</bean>
<bean id="testTime2" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail"> <ref bean="testTask2"/> </property> <!-- 第2个定时任务的目标类和方法 -->
<property name="cronExpression"> <value>0 0 23 * * ?</value> </property> <!-- 每天23时 -->
</bean>
<!-- 调度工厂 -->
<bean id="startQuertz" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="testTime"/>
<ref local="testTime2"/> <!-- 第2个定时触发器 -->
</list>
</property>
</bean>
<!-- 定时任务 end -->





3.任务类

package com.wlyd.wms.service.timer;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
* @Title: TestijInfoJob.java
* @Package com.wlyd.wms.service.timer
* @Company
* @Description: 此类实现Quartz定时器的Job,本类作用在于测试定时任务。
* @author
* @date 2015-6-23 下午05:46:55
* @version V2.0
*/
public class TestijInfoJob{

private Logger log = Logger.getLogger(TestijInfoJob.class);


/**
*
*/
@Transactional(propagation = Propagation.REQUIRED)
public void execute(){
log.info("TestijInfoJob开始执行!!");
try{
System.out.print("测试定时任务。。。。。。。。。。。。。。。。");
log.info("TestijInfoJob已执行!!");
}catch(Exception ex){
log.error("TestijInfoJob执行出错"+ex.getMessage());
}
log.info("TestijInfoJob结束执行!!");
}

public static void main(String[] args){

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
TestijInfoJob ctjj = new TestijInfoJob();
try {
ctjj.execute();
} catch (Exception e) {
e.printStackTrace();
}

}

}

4.cronExpression时间设置规则

org.springframework.scheduling.quartz.CronTriggerBean允许你更精确地控制任务的运行时间,只需要设置其cronExpression属性。
一个cronExpression表达式有至少6个(也可能是7个)由空格分隔的时间元素。从左至右,这些元素的定义如下:

4.1每个时间元素的意义

1.秒(0–59) , - * /
2.分钟(0–59) , - * /
3.小时(0–23) , - * /
4.月份中的日期(1–31) , - * ? / LW C
5.月份(1–12或JAN–DEC) ,- * /
6.星期中的日期(1–7或SUN–SAT) ,- * ? / L C #
7.年份(可选)留空(1970–2099),- * /

实例:

0 0 10,14,16 * * ?
每天上午10点,下午2点和下午4点
0 0,15,30,45 * 1-10 * ?
每月前10天每隔15分钟
30 0 0 1 1 ? 2012
在2012年1月1日午夜过30秒时
0 0 8-5 ? * MON-FRI
每个工作日的工作时间

4.2每个元素的设置范围

各个时间可用值如下:

秒0-59 , - * /
分0-59 , - * /
小时0-23 , - * /
日1-31 , - * ? / L W C
月1-12 or JAN-DEC , - * /
周几1-7 or SUN-SAT , - * ? / L C #
年(可选字段) empty, 1970-2099 , - * /

可用值详细分析如下:
“*”——字符可以用于所有字段,在“分”字段中设为"*"表示"每一分钟"的含义。
“?”——字符可以用在“日”和“周几”字段.它用来指定'不明确的值'.这在你需要指定这两个字段中的某一个值而不是另外一个的时候会被用到。在后面的例子中可以看到其含义。
“-”——字符被用来指定一个值的范围,比如在“小时”字段中设为"10-12"表示"10点到12点"。
“,”——字符指定数个值。比如在“周几”字段中设为"MON,WED,FRI"表示"the days Monday, Wednesday, and Friday"。
“/”——字符用来指定一个值的的增加幅度.比如在“秒”字段中设置为"0/15"表示"第0, 15, 30,和45秒"。而"5/15"则表示"第5, 20, 35,和50".在'/'前加"*"字符相当于指定从0秒开始.每个字段都有一系列可以开始或结束的数值。对于“秒”和“分”字段来说,其数值范围为0到59,对于“小时”字段来说其为0到23,对于“日”字段来说为0到31,而对于“月”字段来说为1到12。"/"字段仅仅只是帮助你在允许的数值范围内从开始"第n"的值
“L”——字符可用在“日”和“周几”这两个字段。它是"last"的缩写,但是在这两个字段中有不同的含义。例如,“日”字段中的"L"表示"一个月中的最后一天" ——对于一月就是31号对于二月来说就是28号(非闰年)。而在“周几”字段中,它简单的表示"7" or "SAT",但是如果在“周几”字段中使用时跟在某个数字之后,它表示"该月最后一个星期×" ——比如"6L"表示"该月最后一个周五"。当使用'L'选项时,指定确定的列表或者范围非常重要,否则你会被结果搞糊涂的。
“W”——可用于“日”字段。用来指定历给定日期最近的工作日(周一到周五)。比如你将“日”字段设为"15W",意为: "离该月15号最近的工作日"。因此如果15号为周六,触发器会在14号即周五调用。如果15号为周日,触发器会在16号也就是周一触发。如果15号为周二,那么当天就会触发。然而如果你将“日”字段设为"1W",而一号又是周六,触发器会于下周一也就是当月的3号触发,因为它不会越过当月的值的范围边界。'W'字符只能用于“日”字段的值为单独的一天而不是一系列值的时候。
“L”和“W”可以组合用于“日”字段表示为'LW',意为"该月最后一个工作日"
“#”——字符可用于“周几”字段。该字符表示“该月第几个周×”,比如"6#3"表示该月第三个周五( 6表示周五而"#3"该月第三个)。再比如: "2#1" =表示该月第一个周一而"4#5" =该月第五个周三。注意如果你指定"#5"该月没有第五个“周×”,该月是不会触发的。
“C”——字符可用于“日”和“周几”字段,它是"calendar"的缩写。它表示为基于相关的日历所计算出的值(如果有的话)。如果没有关联的日历,那它等同于包含全部日历。“日”字段值为"5C"表示"日历中的第一天或者5号以后",“周几”字段值为"1C"则表示"日历中的第一天或者周日以后"。
对于“月份”字段和“周几”字段来说合法的字符都不是大小写敏感的。

实例:

"0 0/1 * * * ?" 每天每分钟触发一次

"0 0 */2 * * *" 每天每两个小时 

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

"0 0 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分每分钟一次触发
"0 0/5 14 * * ?"每天从下午2点开始到2:55分结束每5分钟一次触发
"0 0/5 14,18 * * ?"每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发
"0 0-5 14 * * ?"每天14:00至14:05每分钟一次触发
"0 10,44 14 ? 3 WED"三月的每周三的14:10和14: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 0,15,30,45 * 1-10 * ?"     每月前10天每隔15分钟

"30 0 0 1 1 ? 2012"        在2012年1月1日午夜过30秒