目录
在quartz和elastic job中,都是定义一个接口,然后执行execute方法。面对单条数据和多条数据,我们可以进行不同的设计。
本设计是主要运用到了类的继承,在接口中定义execute方法,然后用抽象类去继承,最后让实现类去执行具体的逻辑。子类重写了父类的方法,如果子类调用该方法,运行的是子类的方法,不会运行父类该方法。
一、接口类
首先定义一个接口类,模仿如elastic job 的接口,当定时任务到时,会执行该接口的execute方法
/**
* 假设该类为job框架的接口
* 当定时任务启动时,调用该接口方法
*/
public interface Job {
/**
* 执行作业
*
* @param context 分片上下文信息
*/
void execute(Map<String, Object> context);
}
二、定义基础job类
对应一个抽象基础类,可以处理单条数据的job。可以在接口实现方法中处理一些公共信息,然后在定义一个抽象的execute()方法,让子类去实现它做具体的不同job业务逻辑实现。
/**
* 基础job,不分页
* protected修饰的变量,子类和同一包下都可以访问
*/
public abstract class BaseJob implements Job {
private Logger log = Logger.getLogger(BaseJob.class);
protected String jobName = this.getClass().getName();
protected static final int BATCH_COUNT = 100;//批处理条数
@Override
public void execute(Map<String, Object> context) {
log.info("job start,job name is :" + context.get("jobName"));
execute();
log.info("job end,job name is :" + context.get("jobName"));
}
protected abstract void execute();//定义成子类可以访问到
}
三、定义分页批量处理job
1、一共有多少数据条数据?如果数据特别大是需要分页进行处理的,如果数据小可以作为一个集合来进行处理
2、具体执行每一条的数据处理方法可以在子类中重写;
/**
* 分页处理数据的job
*/
public abstract class BatchJob<T> extends BaseJob {
private Logger log = Logger.getLogger(BaseJob.class);
@Override
public void execute() {
int rows = getTotalCount();
int pages = getPages(rows);
if (pages == 0) {//如果没有重写getTotalCount()方法,pages则为0,那么就当直接一次请求查询解决
pages = 1;
}
log.info("job :" + jobName + ", pages is " + pages);
for (int i = 0; i < pages; i++) {
List<T> dataList = fetchList(getBatchCount());
if (dataList.isEmpty()) {
return;
}
processList(dataList);
}
afterExecute();
}
//待处理数据总条数
protected int getTotalCount() {
return 0;
}
//获取到总的分页数
protected int getPages(int rows) {
int batchCount = getBatchCount();
int mod = rows % batchCount;
if (mod == 0) {
return rows / batchCount;
}
return rows / batchCount + 1;
}
//获取批处理条数
protected int getBatchCount() {
return BATCH_COUNT;
}
//获取待处理数据
protected abstract List<T> fetchList(int batchCount);
//批量处理数据
protected void processList(List<T> dataList) {
if (dataList.isEmpty()) {
return;
}
for (T item : dataList) {
try {
process(item);
} catch (Exception e) {
log.error("Job " + jobName + " : run Exception e", e);
errProcess(item, e);
}
}
}
//处理单条数据
protected void process(T item) {
}
//错误处理
protected void errProcess(T item, Exception e) {
}
//任务处理完之后进行回调
protected void afterExecute(){}
}
四、job例子
/**
* 当数据并不多时,可以直接在job里调用execute方法在service层进行处理
*/
public class BaseJobExample extends BaseJob{
@Override
protected void execute() {
//调用service层方法
System.out.println("BaseJobTest execute");
}
}
/**
* 子类重写父类的方法,运行时根据子类对象会运行子类的方法
* <p>
* 这里没有进行分页查询了,如果数据量大,需要分页进行查询时,
* 可以重写getTotalCount()/getBatchCount()方法进行分页处理
*/
public class BatchJobExample extends BatchJob<Person> {
@Override
protected List fetchList(int batchCount) {
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
return asList(person1, person2, person3);
}
@Override
protected void processList(List<Person> dataList) {
for (Person person : dataList) {
System.out.println(person);
}
}
}
public class JobTest {
@Test
public void test() {
Job baseJob = new BaseJobExample();
Map<String, Object> context1 = new HashMap<String, Object>();
context1.put("jobName", "baseJobTest");
Job batchJob = new BatchJobExample();
Map<String, Object> context2 = new HashMap<String, Object>();
context2.put("jobName", "batchJobTest");
baseJob.execute(context1);
batchJob.execute(context2);
}
}
运行结果如下
INFO 2018-09-12 20:52:40: [demo05.BaseJob.(19)execute] - job start,job name is :baseJobTest
BaseJobTest execute
INFO 2018-09-12 20:52:40: [demo05.BaseJob.(21)execute] - job end,job name is :baseJobTest
INFO 2018-09-12 20:52:40: [demo05.BaseJob.(19)execute] - job start,job name is :batchJobTest
INFO 2018-09-12 20:52:40: [demo05.BaseJob.(20)execute] - job :demo05.BatchJobExample, pages is 1demo02.bean.Person@3cd1f1c8
demo02.bean.Person@3a4afd8d
demo02.bean.Person@1996cd68
INFO 2018-09-12 20:52:40: [demo05.BaseJob.(21)execute] - job end,job name is :batchJobTest