例如有一些需要批量操作的需求接口时,最直白的做法就是把前端传入的对象集合循环调用单独的执行接口进行完成一次批量的操作。
例如单独的添加操作。这时候需要一个批量的操作,最简单粗暴的做法就是批量循环单个service 方法进行保存操作。(这里需要事务声明下来处理异常进行回滚。)如果可以的话可以选择重写一个dao的接口在mybatis这进行循环的操作效率会提高一些。
这个时候又需要一堆的批量的接口,例如批量执行一些任务,批量删除,批量执行一些业务逻辑比较麻烦操作。那可能就需要在业务层又写一堆进行批量调用单个执行方法的方法。
现在用反射来做这些事。
反射的定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
现在由前端告诉后端需要调用的单个执行方法,由后端进行批量的调用这个方法来进行操作。这样接口就少了很多。
代码示例如下
controller
/**
* 批量操作任务
* @param List<TaskBean> 当前任务信息集合
*/
@ResponseBody
@RequestMapping("/json/processInstance/batchExecuteTask")
public List batchExecuteTask(@RequestBody BatchExecuteParam batchExecuteParam) throws Exception {
return workFlowClientService.batchExecuteTask(batchExecuteParam);
}
service 实现类
@Override
@Transactional
public List batchExecuteTask(Object o,BatchExecuteParam batchExecuteParam) throws Exception {
//这个object是具体的service实例,当然这个也可以用反射来获取。
String methodName = batchExecuteParam.getMethodName();
List list = batchExecuteParam.getArgList();
String argClassName = batchExecuteParam.getArgClassName();
//获取实体类的类类型
Class type = Class.forName("com.tansun.workflow.model." + argClassName);
//获得单个执行方法的方法对象。这里每一个单个执行方法都确保只有一个实体参数
Method method = o.getClass().getDeclaredMethod(methodName,type);
//BaseBean是结果对象的父类。如果结果对象没父类可用object代替
List<BaseBean> BeanList = new ArrayList();
if(list != null && !list.isEmpty()){
for(Object bean : list){
JSONObject json = (JSONObject) JSON.toJSON(bean);
//执行方法,第一个参数具体的service实例,第二个参数要和具体方法的参数类型保持一致。
BaseBean processBean = (BaseBean)method.invoke(o,JSONObject.toJavaObject(json,type));
if(FAILED.equals(processBean.getRetCode())){
throw new RuntimeException(processBean.getRetMsg());
}
BeanList.add(processBean);
}
}
return BeanList;
}
参数的实体类
public class BatchExecuteParam implements Serializable {
private static final long serialVersionUID = 1L;
//实体类的集合
private List argList;
//需要调用方法
private String methodName;
//实体类的类名称
private String argClassName;
}
这样做还需要做几个限制来提高代码的可读性和高效性:
1)method.invoke()这个方法第二个参数是一个可变参数,所以对于单个执行的方法都要保证参数个数是一致的
2)只能针对逻辑比较简单的单个执行方法并且少批量的进行调用
3)单个任务的执行中要进行针对执行失败进行一些操作来进行所有的事务的回滚。例如单个执行任务中进行抛出异常。一定要抛异常,不然批量的任务的@Transactional注解不会进行任务回滚。或者像我的代码一样设一个标志。
这的好处就是后端的接口大幅减少,坏处就是执行时间会有所延长,只适合小批量的任务操作。
其实哪个执行单个任务的方法的类型参数也可以不需要传
思路:根据反射获取哪个实例所有的method对象。然后比对方法名是否相同,获取对应的方法对象,在获取这个方法对象参数类型就好了。这里是一个数组,表示这个方法的所有参数类型。
获取第一个参数就好了。
这篇文章只提供了一个参考思路。具体问题具体分析