管中窥quartz(续)spring整合

来源:互联网 发布:杭州下沙美工招聘 编辑:程序博客网 时间:2024/06/14 05:10

前言

在上一篇的小总结中,我们学习了quartz的基本使用API,对quartz中的Job,Trigger,scheduler有所了解,在日常开发中,我们很少会直接使用quartz的原生API进行项目中的任务调度开发,一般我们都是和spring进行整合使用,spring对quartz进行很好的封装,使得我们在开发中对quartz的使用更加灵活,方便。有人可能会想既然spring已经帮我封装了quartz的使用,我们为什么还要去学原来的quartz的使用,其实quartz是一个功能很强大的任务调度框架,很多小伙伴在日常开发中需要用到定时任务,直接在网上百度一下spring整合quartz,然后按照教程去配置任务调度文件,完成自己的功能。就觉得quartz很简单嘛,稍微配置一下,搞定。然后顺便再来一句“看来,我真是个天才!”,其实这种想法是错误的,很多东西使用的功能和细节都是和具体使用的环境有关系的,就比方说,你用在任务中输出打印一个日志,你觉得很简单,但是你要在任务处理大数据量的增删该查的时候,项目中有很多任务需要处理,你的并发调用,还有任务调度线程是怎么优化,任务调度的集群配置又该如何使用,等等这些,不要觉得那些东西等到你使用的时候再去找百度也一样。其实我觉得是不一样的,上课之前提前预习的道理谁都懂,但是有多少人做到预习呢!扯远了。。。下面开始spring和quartz的整合。

基础依赖的注入

既然是spring和quartz的整合,肯定是先导入相关的jar,这里是Maven环境,所以直接在pom.xml中进行配置就行了,本文中所使用的演示环境是jdk8,tomcat7,这里需要注意的一点是,在jdk8可能会和低版本的tomcat不兼容,有可能会启动报错,这里只是升级tomcat的版本就ok了。由于这里不涉及到其他的框架和功能,所以pom.xml文件中就只有简单quartz依赖和spring依赖。具体配置文件如下

<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/maven-v4_0_0.xsd">  <modelVersion>4.0.0</modelVersion>  <groupId>com.aiqinhai</groupId>  <artifactId>quartz</artifactId>  <packaging>war</packaging>  <version>0.0.1-SNAPSHOT</version>  <name>quartz Maven Webapp</name>  <url>http://maven.apache.org</url>  <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <spring.version>4.3.6.RELEASE</spring.version>    </properties>    <dependencies>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>3.8.1</version>            <scope>test</scope>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-webmvc</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-aop</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-context-support</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-tx</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.quartz-scheduler</groupId>            <artifactId>quartz</artifactId>            <version>2.2.3</version>        </dependency>    </dependencies>    <build>        <finalName>quartz</finalName>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <configuration>                    <source>1.8</source>                    <target>1.8</target>                </configuration>            </plugin>        </plugins>    </build></project>

具体任务类的配置

上面是相关依赖的jar,接下来我们就需要具体的任务调度类

public class FirstScheduledJob extends QuartzJobBean{     private AnotherBean anotherBean;     public void setAnotherBean(AnotherBean anotherBean){         System.out.println("这里进行调用给anotherBean进行赋值了");         this.anotherBean = anotherBean;     }    @Override    protected void executeInternal(JobExecutionContext arg0)            throws JobExecutionException {        Date date = new Date();        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        System.out.println("FirstScheduledJob Executes!" + sf.format(date));        this.anotherBean.printAnotherMessage();         }}

注意上面的任务类是继承了QuartzJobBean,这是spring中任务调度类的一种,我们需要在配置文件中进行配置

    <bean id="firstComplexJobDetail"        class="org.springframework.scheduling.quartz.JobDetailFactoryBean">        <property name="jobClass" value="com.aiqinhai.FirstScheduledJob" />        <property name="jobDataMap">            <map>                <entry key="anotherBean" value-ref="anotherBean" />            </map>        </property>        <property name="Durability" value="true"/>                  </bean>

上面的配置文件中,我们将anotherBean对象通过jobDataMap传递给了FirstScheduledJob任务调度器,这在日常开发中,我们可以将一些service接口通过jobDataMap传递给需要使用这些接口的任务类。然后在任务类中调用这些接口中的方法。
上面是使用继承的方式来实现具体的任务类,然后在人物类中进行具体的逻辑操作,下面这种任务类配置是不需要继承任何类的,任务类如下

@Component("myBean")public class MyBean {    public void printMessage() {        Date date = new Date();        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        System.out.println("MyBean Executes!" + sf.format(date));    }}

这种任务类需要在配置文件中进行另外的配置,如下

<bean id="simpleJobDetail"    class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">    <property name="targetObject" ref="myBean" />    <property name="targetMethod" value="printMessage" /></bean>

这样两种任务类的配置完成,我们还需要给每个任务配置具体的调度策略,对于spirng整合quratz的调度策略也是有两种写法,第一种是简单的任务调用策略,这种方式比较适合哪种定间隔,定频率的任务调度触发策略,具体如下

<!-- 距离当前时间1秒之后执行,之后每隔两秒钟执行一次 --><bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">    <property name="jobDetail"  ref="simpleJobDetail"/>    <property name="startDelay"  value="1000"/>    <property name="repeatInterval"  value="2000"/></bean>

另外是一种任务触发方式,功能更加强大,这也是quartz比java原生Timer更受欢迎的原因之一。

<!-- 每隔5秒钟执行一次 --><bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">    <property name="jobDetail"  ref="firstComplexJobDetail"/>    <property name="cronExpression"  value="0/5 * * ? * *"/></bean>

上面就是所谓CronTrigger调度器,通过cron表达式,我们能够配置功能十分强大的任务调度策略,很多SimpleTrigger不能完成的调度策略,CronTrigger是完全可以实现的,这都依赖于cron表达式的强大配置。对于corn表达式的介绍,我在后面会和大家一起总结。
配置好了,任务,触发策略,接下来,我们就需要将任务和触发器注册到一个任务调用容器中,当容器启动之后,容器里面的任务就会依据配置的触发策略进行任务执行。下面就是在配置文件中的具体任务调度器配置

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">   <property name="jobDetails">        <list>            <ref bean="simpleJobDetail"/>            <ref bean="firstComplexJobDetail"/>        </list>    </property>    <property name="triggers">        <list>            <ref bean="mySimpleTrigger"/>            <ref bean="myCronTrigger"/>        </list>    </property></bean>

整合和上面的基础,整个spring和quartz的整合就已经大体完成了。

Cron表达式

一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素。
按顺序依次为
秒(0~59)
分钟(0~59)
小时(0~23)
天(月)(0~31,但是你需要考虑你月的天数)
月(0~11)
天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
7.年份(1970-2099)
其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符。由于”月份中的日期”和”星期中的日期”这两个元素互斥的,必须要对其中一个设置?.
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触发
有些子表达式能包含一些范围或列表
例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”
“*”字符代表所有可能的值
因此,“”在子表达式(月)里表示每个月的含义,“”在子表达式(天(星期))表示星期的每一天
“/”字符用来指定数值的增量
例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟
在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样
“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值
当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”
“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
但是它在两个子表达式里的含义是不同的。
在天(月)子表达式中,“L”表示一个月的最后一天
在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT
如果在“L”前有具体的内容,它就具有其他的含义了
例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五
注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题
字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空, 1970-2099 , - * /

总结

上面是简单的对spirng整合quartz的介绍,对于quartz的集群配置,还有一场处理,以及任务调度优化,后面会和大家一起在总结学习!

原创粉丝点击