Spring与Quartz的整合实现定时任务调度
Quartz集成Spring的2个方法
关于Spring集成Quartz有2种方法:
1. JobDetailBean.
2. MethodInvokeJobDetailFactoryBean.
以下从自身使用和理解以及掌握的知识对其进行阐述。
需要注意的是,在使用Spring集成Quartz的时候,一定不要忘记引入spring-support这个包:
1、使用 MethodInvokeJobDetailFactoryBean
applicationTask.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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- 定时任务 下游回调任务--> <!-- ======================== 1、定义需要执行的任务类。 ======================== --> <bean id="notifyQuartz" class="com.hsmpay.mobile.timerTask.NotifyTimerAction"> </bean> <!-- ======================== 2、将需要执行的定时任务注入JOB中。 ======================== --> <bean id="notifyQuartzDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <!--引入执行任务的类--> <property name="targetObject"><ref bean="notifyQuartz"/></property> <!--定义要执行具体类的方法--> <property name="targetMethod"><value>remoteNotify</value></property> </bean> <!-- ======================== 3、调度触发器 ======================== --> <bean id="notifyTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail"><ref bean="notifyQuartzDetail"/></property> <property name="cronExpression"> <!--每五分钟执行一次--> <!--<value>0 08 10 * * ?</value>--> <value>0 0/5 * * * ?</value><!--<value>秒 分 时 天 月 周 年</value> 0 55 17 ? * MON-FRI--> </property> </bean> <!--================================================================================================--> <!-- 半分钟执行定时任务 --> <!-- ======================== 1、定义需要执行的任务类。 ======================== --> <bean id="messageTask" class="com.hsmpay.mobile.timerTask.MessageTask"></bean> <!-- ======================== 2、将需要执行的定时任务注入JOB中。 ======================== --> <bean id="oneMessageRollBackTaskJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject"><ref bean="messageTask"/></property> <property name="targetMethod"><value>oneTaskJob</value></property> </bean> <!-- ======================== 3、调度触发器 ======================== --> <bean id="oneMessageStreamRollBackTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail"> <ref bean="oneMessageRollBackTaskJobDetail"/> </property> <property name="cronExpression"> <value>*/30 * * * * ?</value> </property> </bean> <!-- ======================== 4、调度工厂 ======================== --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="notifyTrigger"/> </list> </property> </bean> <bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 线程池维护线程的最少数量 --> <property name="corePoolSize" value="10" /> <!-- 线程池维护线程所允许的空闲时间 --> <property name="keepAliveSeconds" value="200" /> <!-- 线程池维护线程的最大数量 --> <property name="maxPoolSize" value="50" /> <!-- 线程池所使用的缓冲队列 --> <property name="queueCapacity" value="100" /> <property name="rejectedExecutionHandler"> <!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 --> <!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 --> <!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 --> <!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 --> <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" /> </property> </bean> </beans>
相关代码配置
@Controller("notifyTimerAction") public class NotifyTimerAction { private Logger log = LoggerFactory.getLogger(this.getClass()); @Resource(name="transOrderService") TransOrderService transOrderService;//查询订单service //设置核心池大小 int corePoolSize = 5; //设置线程池最大能接受多少线程 int maximumPoolSize=20; //当前线程数大于corePoolSize、小于maximumPoolSize时,超出corePoolSize的线程数的生命周期 long keepActiveTime = 200; //设置时间单位,秒 TimeUnit timeUnit = TimeUnit.SECONDS; public String url ="http://localhost:8080/mobile/forwardPort/port.action"; /** * 下游回调通知,继续发送 */ public void remoteNotify() throws Exception{ log.debug("test定时任务启动了!!!!!!!!"); System.out.println("test定时任务启动了!!!!!!!!"); TransOrder order=new TransOrder(); order.setStatus(1);//设置成功状态 order.setClientType(7);//设置客户类型 7外放接口类型 order.setOrderTypeId(1L);//收款类型 //设置线程池缓存队列的排队策略为FIFO,并且指定缓存队列大小为5 BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(5); //创建ThreadPoolExecutor线程池对象,并初始化该对象的各种参数 ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepActiveTime, timeUnit,workQueue); try { List<TransOrder> orderList = transOrderService.searchEntityList(order); Map<String,Object> map=new HashMap<String,Object> (); //准备给下游发送数据 for(TransOrder transOrder:orderList){ Thread thread=new Thread(new Runnable() { public void run() { map.put("status",transOrder.getStatus());//交易状态 map.put("orderNum",transOrder.getOrderNum());//订单号 JSONObject jsonObject = JSONObject.fromObject(map); HttpClientUtil.submitPost(transOrder.getOtherData(), map.toString(), "UTF-8",60000, 60000); } }); executor.execute(thread); } executor.shutdown();//关闭线程池 } catch (Exception e) { e.printStackTrace(); throw e; } } }
==================================================================================================================================================================
二、JobDetailBean
1. 创建一个Job方法,此方法必须继承QuartzJobBean或者实现Job方法。
public class TestJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException { System.out.println(TimeUtils.getCurrentTime()); } }
2. 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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="com.mc.bsframe.job.TestJob"></property> <property name="durability" value="true"></property> </bean> <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="jobDetail" /> <property name="startDelay" value="3000" /> <property name="repeatInterval" value="2000" /> </bean> <!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 --> <bean id="startQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!-- 管理trigger --> <property name="triggers"> <list> <ref bean="simpleTrigger" /> </list> </property> </bean> </beans>
综上:定时任务的基本配置完成。
三、两种方法的说明
使用QuartzJobBean,需要继承。而使用MethodInvokeJobDetailFactoryBean则需要指定targetObject(任务实例)和targetMethod(实例中要执行的方法)
后者优点是无侵入,业务逻辑简单,一目了然,缺点是无法持久化(目前还不太清楚这点!)
从我使用的经验来说,我更推荐的第一种,其中一个很重要的原因就是因为定时任务中注入相关Service的时候,后者可以直接注入,而前者还需要进行Schedular的替换修改。