一. 应用场景
在我们进行软件开发过程中,会遇到这样的场景,比如在凌晨的时候进行数据的统一刷新;每个月末进行用户数据的统计;定期清理不用的数据等等,这时候就要用到定时任务来进行处理了
二.实现技术
从 技术上说实现定时任务常见的方法有三种
- Java自带的java.util.Timer类
- 使用Quartz调度器,这种方式需要第三方jar支持
- Spring3.0以后自带的task定时器
由于目前项目中spring框架应用的非常广泛,故本文将直接介绍与spring结合的Quartz定时任务技术。采用普通类+xml配置文件的方式进行多个定时任务的启动。
三.项目搭建
1. 创建maven项目
转换添加web.xml文件
pom.xml文件
2. 在web.xml 中添加监听器
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring/application-context.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3.添加spring-context.xml文件和编写定时任务类QuartOne以及QuartzTwo两个类
4. 添加配置文件
4.1 由于是与Quartz结合故pom.xml 中要添加quartz的相关jar包
4.2 spring-context.xml 中配置内容
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 注册任务的类 -->
<bean id="one" class="com.xing.deng.QuartzOne"/>
<bean id="two" class="com.xing.deng.QuartzTwo"/>
<!-- 1:定时任务 start-->
<bean id="oneDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" >
<!-- 指定任务类 -->
<property name="targetObject" ref="one"/>
<!-- 指定任务执行的方法 -->
<property name="targetMethod" value="execute"/>
<!-- 不并发调度 -->
<property name="concurrent" value="false"></property>
</bean>
<bean id="oneCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="oneDetail"/>
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
<!-- 1:定时任务 end -->
<!-- 2:定时任务 start -->
<bean id="twoDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" >
<!-- 指定任务类 -->
<property name="targetObject" ref="two"/>
<!-- 指定任务执行的方法 -->
<property name="targetMethod" value="execute"/>
<property name="concurrent" value="false"></property>
</bean>
<bean id="twoCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="twoDetail"/>
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
<!-- 2:定时任务 end -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="oneCronTrigger"/>
<ref bean="twoCronTrigger"/>
</list>
</property>
</bean>
</beans>
4.3 配置说明
注意上面的标注一定要一一对应!!!
5. 启动tomcat后执行结果
参考来源:http://blog.youkuaiyun.com/harry_zh_wang/article/details/60782780
6.项目优化
6.1 目标
针对上面的定时任务,我们是否可以定义这样一个抽象的类,统一固定的执行任务方法,那么其他的定时任务只需继承这个抽象类,那样就能避免项目中每个人写不同的定时任务执行方法了(这种方式在java中就是叫做:抽象)。
既然目的清楚,那我们就开始coding.
6.2 搭建
创建抽象类 :AbstractQuartz
创建子类:FirstQuartz 和SecondQuartz
编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 1. 注册任务的类 -->
<bean id="firstQuartz" class="com.xing.deng.quartz.FirstQuartz"/>
<bean id="secondQuartz" class="com.xing.deng.quartz.SecondQuartz"/>
<!--2. 配置作业类 -->
<bean id="abstractQuartzDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" abstract="true">
<property name="targetMethod" value="handler"/>
</bean>
<bean id="abstractTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean" abstract="true"/>
<!--3. 配置任务调度触发器 -->
<bean id="firstTrigger" parent="abstractTrigger">
<property name="jobDetail">
<bean parent="abstractQuartzDetail">
<property name="targetObject" ref="firstQuartz"/>
</bean>
</property>
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
<bean id="secondTrigger" parent="abstractTrigger">
<property name="jobDetail">
<bean parent="abstractQuartzDetail">
<property name="targetObject" ref="secondQuartz"/>
</bean>
</property>
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
<!--4. 配置任务调度工厂 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="firstTrigger"/>
<ref bean="secondTrigger"/>
</list>
</property>
</bean>
</beans>
说明:
我们通过配置文件可以看到,在配置作业类的时候,增加了 abstract="true" ,同时其他任务出发器只需注明父类即可统一执行指定的方法,是不是觉得这样的方式十分的统一方便
7. cron 表达式
说明:
1)Cron表达式的格式:秒 分 时 日 月 周 年(可选)。
字段名 允许的值 允许的特殊字符
秒 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 , - * /
“?”字符:表示不确定的值
“,”字符:指定数个值
“-”字符:指定一个值的范围
“/”字符:指定一个值的增加幅度。n/m表示从n开始,每次增加m
“L”字符:用在日表示一个月中的最后一天,用在周表示该月最后一个星期X
“W”字符:指定离给定日期最近的工作日(周一到周五)
“#”字符:表示该月第几个周X。6#3表示该月第3个周五
2)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 * * ?