本任务处理模板使用maven管理具体jar包依赖,使用quartz2.2.2搭建的一个定时任务处理模板,模板提供了一个CommonJob类用于quartz调用,此类的作用是处理任务模板类,规定了处理任务的步骤为:①获取待处理任务列表;②遍历待处理任务列表,逐一进行处理。然后只需要注入一个具体的任务类,此任务类可注入相应的业务处理service,service需实现CommonJobService中各个方法,service中相应方法可声明事物,以便模板类调用完成具体任务处理流程。
具体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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.defonds.scheduler" />
<!-- 具体的任务action需要实现commonJobService内各方法 -->
<bean id="fileReadTask" class="com.action.FileReadTaskAction">
<property name="fileReadService" ref="fileReadService"></property>
</bean>
<bean id="fileReadService" class="com.service.impl.FileReadServiceImpl">
</bean>
<bean id="commonJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<!-- 为commonJob模板注入具体的任务action -->
<bean class="com.job.CommonJob">
<property name="autoTaskAction" ref="fileReadTask"></property>
<property name="threadPoolSize" value="5"></property>
</bean>
</property>
<property name="targetMethod" value="execute"></property>
</bean>
<!-- Run the job every 5 seconds -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="commonJob" />
<property name="cronExpression" value="0/5 * * * * ?" />
</bean>
<!-- Scheduler factory bean to glue together jobDetails and triggers to Configure Quartz Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="commonJob" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
</beans>
commonJob类代码如下:
package com.job;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import com.common.AutoTask;
import com.common.Transaction;
public class CommonJob{
private static Logger logger = LoggerFactory.getLogger(CommonJob.class);
private String threadPoolSize;
private AutoTask autoTaskAction;// 注入的任务
private Map dupMap = new ConcurrentHashMap();
// 定时任务执行入口方法
public void execute() throws Exception{
List<Object> list = autoTaskAction.fetchData();// 获取待处理状态任务数据
ExecutorService threadPool = Executors.newFixedThreadPool(Integer.parseInt(threadPoolSize));
// 遍历获取的待处理任务列表
for(Object data:list){
int uniqueId = autoTaskAction.getUniqueId(data);
// 对任务做防重处理
if(checkDup(uniqueId)){
logger.debug("This transaction is under processing now : "+uniqueId);
continue;// 若任务已在 处理,则暂不处理该任务,开始处理下一个任务
}
//检查任务是否为待处理状态(任务为状态驱动,再次确认任务是否为待处理状态,若是则继续处理,否则说明已正在被处理或已处理完)
if(!checkStatus(uniqueId)){
logger.debug("This transaction is not in wait-process status : "+uniqueId);
continue;
}
// 将任务包装为Runnable
RunnableTask task = new RunnableTask(data);
// 提交给线程池执行
threadPool.execute(task);
}
threadPool.shutdown();
}
protected boolean checkDup(int uniqueId){
// job类内部维护一个防重表,若无此任务ID,则放置入Map,若已存在,则说明任务已在处理
if(dupMap.get(uniqueId) == null){
dupMap.put(uniqueId, "");
return false;
}else{
return true;
}
}
protected boolean checkStatus(int uniqueId){
//根据ID获取任务详情
Transaction t = autoTaskAction.loadTransactionById(uniqueId);
//若任务状态仍未待处理则检查成功,继续处理任务,否则false,不处理该任务
if("wait_process".equals(t.getStatus())){
return true;
}else{
return false;
}
}
public class RunnableTask implements Runnable{
private Object data;
// 构造方法需将任务实体传入
public RunnableTask(Object data){
this.data = data;
}
public void run() {
int uniqueId = autoTaskAction.getUniqueId(data);
try{
// 调用注入的任务类处理任务方法处理任务
autoTaskAction.deal(data);
}catch(Exception e){
e.printStackTrace();
}finally{
// 处理完任务或抛出异常时均在防重map中将任务ID删除
dupMap.remove(uniqueId);
}
}
}
public void setThreadPoolSize(String threadPoolSize) {
threadPoolSize = threadPoolSize;
}
public void setAutoTaskAction(AutoTask autoTaskAction) {
this.autoTaskAction = autoTaskAction;
}
}
该类提供了任务处理模板,其中execute方法为quartz定时任务入口方法(xml中设置),负责获取待处理任务列表,初始化线程池,遍历待处理任务列表,依次处理。其中我们将任务处理方法封装进内部Runnable类,以便利用线程池更快处理任务列表。任务处理时注意防重及任务状态确认,防止重复处理
以下为具体任务处理action及接口方法类:
package com.action;
import java.util.List;
import com.common.AutoTask;
import com.common.Transaction;
import com.service.CommonJobService;
public class FileReadTaskAction implements AutoTask{
private CommonJobService fileReadService;
public List<Object> fetchData() {
List<Object> list = fileReadService.fetchData();
return list;
}
public int getUniqueId(Object data) {
Transaction t = (Transaction)data;
return t.getTransId();
}
public void deal(Object data) {
fileReadService.deal(data);
}
public Transaction loadTransactionById(int transId) {
return (Transaction)fileReadService.loadTransactionById(transId);
}
public void setFileReadService(CommonJobService fileReadService) {
this.fileReadService = fileReadService;
}
}
package com.common;
import java.util.List;
public interface AutoTask {
public List<Object> fetchData();
public int getUniqueId(Object data);
public void deal(Object data);
public Transaction loadTransactionById(int transId);
}
package com.service;
import java.util.List;
import com.common.Transaction;
public interface CommonJobService {
public List<Object> fetchData();
public void deal(Object data);
public Transaction loadTransactionById(int transId);
}
最后为quartz的IOC容器启动类,通过run as java application即可实现定时处理任务
package com.auto;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App
{
public static void main( String[] args )
{
ApplicationContext applicationContext = null;
try {
//获取配置文件,启动IOC容器
applicationContext = new ClassPathXmlApplicationContext("classpath*:quartz.xml");
System.out.println("AutoHandler is started successfully!!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
后修正了CommonJob.java的线程池生成方式,实现了InitializingBean接口,通过注解@value注入线程池PoolSize参数,让他在bean刚开始实例化后即产生线程池,完成任务列表后无需关闭线程池,等待下次任务周期再次复用即可。这样整个bean的生命周期只用创建一次固定大小线程池,省去了多次创建、销毁线程池的开销。代码如下:
package com.job;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import com.common.AutoTask;
import com.common.Transaction;
public class CommonJob implements InitializingBean{
private static Logger logger = LoggerFactory.getLogger(CommonJob.class);
@Value("${commonJob.threadPoolSize}")
private String threadPoolSize;
private AutoTask autoTaskAction;// 注入的任务
private Map dupMap = new ConcurrentHashMap();
private ExecutorService threadPool;
// 定时任务执行入口方法
public void execute() throws Exception{
List<Object> list = autoTaskAction.fetchData();// 获取待处理状态任务数据
//ExecutorService threadPool = Executors.newFixedThreadPool(Integer.parseInt(threadPoolSize));
// 遍历获取的待处理任务列表
for(Object data:list){
int uniqueId = autoTaskAction.getUniqueId(data);
// 对任务做防重处理
if(checkDup(uniqueId)){
logger.debug("This transaction is under processing now : "+uniqueId);
continue;// 若任务已在 处理,则暂不处理该任务,开始处理下一个任务
}
//检查任务是否为待处理状态(任务为状态驱动,再次确认任务是否为待处理状态,若是则继续处理,否则说明已正在被处理或已处理完)
if(!checkStatus(uniqueId)){
logger.debug("This transaction is not in wait-process status : "+uniqueId);
continue;
}
// 将任务包装为Runnable
RunnableTask task = new RunnableTask(data);
// 提交给线程池执行
threadPool.execute(task);
}
}
protected boolean checkDup(int uniqueId){
// job类内部维护一个防重表,若无此任务ID,则放置入Map,若已存在,则说明任务已在处理
if(dupMap.get(uniqueId) == null){
dupMap.put(uniqueId, "");
return false;
}else{
return true;
}
}
protected boolean checkStatus(int uniqueId){
//根据ID获取任务详情
Transaction t = autoTaskAction.loadTransactionById(uniqueId);
//若任务状态仍未待处理则检查成功,继续处理任务,否则false,不处理该任务
if("wait_process".equals(t.getStatus())){
return true;
}else{
return false;
}
}
public class RunnableTask implements Runnable{
private Object data;
// 构造方法需将任务实体传入
public RunnableTask(Object data){
this.data = data;
}
public void run() {
int uniqueId = autoTaskAction.getUniqueId(data);
try{
// 调用注入的任务类处理任务方法处理任务
autoTaskAction.deal(data);
}catch(Exception e){
e.printStackTrace();
}finally{
// 处理完任务或抛出异常时均在防重map中将任务ID删除
dupMap.remove(uniqueId);
}
}
}
/*public void setThreadPoolSize(String threadPoolSize) {
threadPoolSize = threadPoolSize;
}*/
public void setAutoTaskAction(AutoTask autoTaskAction) {
this.autoTaskAction = autoTaskAction;
}
@Override
public void afterPropertiesSet() throws Exception {
threadPool = Executors.newFixedThreadPool(Integer.parseInt(threadPoolSize));
}
}