轻松搞定Spring+quartz的定时任务
1.spring 的定时任务写法有两种:一种是继承工作类,一种是普通的Bean,定时写法有两种写法:一种是以时间间隔启动任务SimpleTriggerBean,一种是以时刻启动任务CronTriggerBean
2.这里介绍第二种写法
- 先创建一个普通的作业类,就是要执行自己业务的类
- 配置spring 的配置文件
普通作业类
package com.sgfm.datacenter.action.quartz; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.HashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.poi.util.SystemOutLogger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.sgfm.base.action.BaseAction; import com.sgfm.base.util.AESUtil; import com.sgfm.datacenter.SysConstant; import com.sgfm.datacenter.entity.TMember; import com.sgfm.datacenter.exception.AppException; import com.sgfm.datacenter.service.health.RecordExplainService; import com.sgfm.datacenter.util.JsonResponseResult; import com.sgfm.datacenter.util.SysUtils; import net.sf.json.JSONObject; /* * 定时更新体检订单表的状态,在spring 配置文件托管bean */ public class UpdOrderEndTimeAction extends BaseAction{ private static final long serialVersionUID = 1L; private Log logger = LogFactory.getLog(this.getClass()); @Autowired private RecordExplainService recordExplainService ; //更新方法 public String updateOrderInfo(){ try{ logger.info("开始执行定时任务"); recordExplainService.updOrderState(); }catch(AppException app){ app.printStackTrace(); logger.info("定时任务执行异常======UpdOrderEndTimeAction---->updateOrderInfo"); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); logger.info("时任务执行异常=======UpdOrderEndTimeAction---->updateOrderInfo"); logger.info(""); } return null; }
//更新第二个表 public void updateTjAndGjOrder(){ try{ logger.info("开始执行定时任务2"); }catch(AppException app){ app.printStackTrace(); logger.info("定时任务执行异常======UpdOrderEndTimeAction---->updateOrderInfo"); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); logger.info("定时任务执行异常=======UpdOrderEndTimeAction---->updateOrderInfo"); logger.info(""); } }
}
spring 任务配置,要记得将quartz的相关jar包导入
<?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:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-lazy-init="false">
<!--=========================================================写法1========================================================================--> <!-- task --> <!-- 定义了一个任务 --> <bean id="quartzClock" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass"> <value>com.sgfm.datacenter.quartz.DimingUpdateAllCache</value> </property> </bean> <bean id="quartzClock2" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass"> <value>com.sgfm.datacenter.quartz.DimingUpdateSectionCache</value> </property> </bean> <!-- 这种配置可以精确几点执行定时任务 --> <!-- 定义了任务的执行方式 --> <bean id="cronQuartzClock" class="org.springframework.scheduling.quartz.CronTriggerBean" > <property name="jobDetail"> <ref bean="quartzClock"></ref> </property> <property name="cronExpression"> <value>0 0 3 4/4 * ? </value> <!-- 服务启动之后,从第四天开始执行任务,之后每四天执行一次--> </property> </bean> <!-- 服务启动半小时秒之后运行 然后每一个小时执行一次任务 --> <bean id="quartzClockTask" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail"> <ref bean="quartzClock2"/> </property> <property name="startDelay"><!--这里是服务启动后延时多少时间,开始计时任务,单位ms--> <value>3600000</value> </property> <property name="repeatInterval"><!--这里是每隔多长时间就进行一次计时任务,单位ms--> <value>3600000</value> </property> </bean> <!--第三步 启动定时任务,注意这里的ref bean --> <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronQuartzClock"></ref> <ref bean="quartzClockTask"></ref> </list> </property> </bean> <!-- ============================================================写法二 ============================================================--> <!-- 托管bean 默认单例模式 --> <bean id="UpOrderBean" class="com.sgfm.datacenter.action.quartz.UpdOrderEndTimeAction"/> <!-- 定义任务的执行方法 --> <bean id="upOrderTask" class= "org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ><ref bean="UpOrderBean"/></property> <property name="targetMethod" ><value>updateOrderInfo</value></property> <!-- false 表示非并发执行 --> <property name="concurrent" value =" false " /> </bean> <!-- 配置触发器,自定义触发时机 ,SimpleTriggerBean 每隔一段时间执行--> <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="upOrderTask" /> <property name="startDelay" value="0" /><!-- 调度工厂实例化后,经过0秒开始执行调度 --> <property name="repeatInterval" value="300000" /><!-- 每5分钟调度一次 --> </bean>
<!-- 任务描述2 --> <bean id="upOrderTask2" class= "org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ><ref bean="UpOrderBean"/></property> <property name="targetMethod" ><value>updateTjAndGjOrder</value></property> <!-- false 表示串行执行 --> <property name="concurrent" value =" false " /> </bean> <bean id="simpleTrigger2" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="upOrderTask2" /> <property name="startDelay" value="0" /><!-- 调度工厂实例化后,经过0秒开始执行调度 --> <property name="repeatInterval" value="300000" /><!-- 每5分钟调度一次 --> </bean>
<!-- 调度工厂 --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="simpleTrigger" />
<ref bean="simpleTrigger2" />
</list> </property> </bean> </beans>
方法2:定义了两个触发器,执行不同的方法。
这里说一下concurrent 这个属性:
1.场景:作业类A ,作业方法methodA(), 当作业A的bean 是一个无状态的bean 的时候,上一次执行A 的方法methodA的时间超过执行间隔时,下一次执行A的方法methodA又开始执行,这时候就会发生同一个作业的类的同一个方法并行执行。可能造成的后果是重复入库,数据库数据混乱。
解决方式是:将concurrent=“false” false 表示不允许并行执行,当上一次的任务执行完毕之后再执行下一次的任务
300000