使用函数式接口对代码简化,完成代码重复性使用
📚简介
???????因为公司的使用Xxl-Job作为任务调度平台,其中我们大部分的报表查询数据量太大,字段又多,实时查询效率太低,等待时长也久,我们只能把常用的数据进行定时任务处理,每几分钟自动运行程序跑对应报表的Sql插入缓存表中,页面端在通过缓存表进行渲染,使用这点有个不好之处就是有个定时任务的执行时间差,关于订单业绩相关的我们任务设置的时间就短,尽量不影响使用者.
???????所以这个时间我们需要传递查询指定时间范围内,或者是不指定时间而是指定运行前多少天的数据进行重跑处理.最终参数定义了常用的三个参数
{
"beginTime":"",
"endTime":"",
"beforeDays":"10"
}
xxl-job 的参数接收类
💨优化前原代码:
伪代码:缓存定时任务
/**
* @Author itmei
* @Date 2023/12/22 20:48
* @description: 任务处理器
* @Title: CacheTaskHandle
* @Package com.itmei.xxl.task
*/
@Component
public class CacheTaskHandle {
@XxlJob("bxCacheTableTask")
public ReturnT<String> bxCacheTableTask() throws Exception {
long start = System.currentTimeMillis();
//获取xxl-job调度传递过来的数据
String param = XxlJobHelper.getJobParam();
XxlJobHelper.log("###### Job参数 ######\n{}",param);
XxlJobParam jobParam;
if (ObjectUtil.isNotEmpty(param)) {
jobParam = JSONUtil.toBean(param, XxlJobParam.class);
} else {
jobParam = new XxlJobParam();
}
DateTime beginTime;
DateTime endTime;
if (ObjectUtil.isEmpty(jobParam.getBeginTime()) || ObjectUtil.isEmpty(jobParam.getEndTime())) {
DateTime startDateTime;
DateTime endDateTime = DateUtil.date();
Integer beforeDays = jobParam.getBeforeDays();
if (ObjectUtil.isEmpty(beforeDays)) {
//默认开始时间是当前时间向之前偏移46天
startDateTime = DateUtil.offsetDay(new Date(), -46);
} else {
startDateTime = DateUtil.offsetDay(new Date(), -Integer.valueOf(beforeDays));
}
beginTime = DateUtil.beginOfDay(startDateTime);
endTime = DateUtil.endOfDay(endDateTime);
} else {
//处理时间范围
beginTime = DateUtil.beginOfDay(jobParam.getBeginTime());
endTime = DateUtil.endOfDay(jobParam.getEndTime());
}
bxCacheHandle(beginTime,endTime);
long end = System.currentTimeMillis();
XxlJobHelper.log("###### Job执行完成,耗时: {} 秒 ######",(end-start)/1000);
return ReturnT.SUCCESS;
}
@XxlJob("bwmCacheTableTask")
public ReturnT<String> bwmCacheTableTask() throws Exception {
long start = System.currentTimeMillis();
//获取xxl-job调度传递过来的数据
String param = XxlJobHelper.getJobParam();
XxlJobHelper.log("###### Job参数 ######\n{}",param);
XxlJobParam jobParam;
if (ObjectUtil.isNotEmpty(param)) {
jobParam = JSONUtil.toBean(param, XxlJobParam.class);
} else {
jobParam = new XxlJobParam();
}
DateTime beginTime;
DateTime endTime;
if (ObjectUtil.isEmpty(jobParam.getBeginTime()) || ObjectUtil.isEmpty(jobParam.getEndTime())) {
DateTime startDateTime;
DateTime endDateTime = DateUtil.date();
Integer beforeDays = jobParam.getBeforeDays();
if (ObjectUtil.isEmpty(beforeDays)) {
//默认开始时间是当前时间向之前偏移46天
startDateTime = DateUtil.offsetDay(new Date(), -46);
} else {
startDateTime = DateUtil.offsetDay(new Date(), -Integer.valueOf(beforeDays));
}
beginTime = DateUtil.beginOfDay(startDateTime);
endTime = DateUtil.endOfDay(endDateTime);
} else {
//处理时间范围
beginTime = DateUtil.beginOfDay(jobParam.getBeginTime());
endTime = DateUtil.endOfDay(jobParam.getEndTime());
}
bwmCacheHandle(beginTime,endTime);
long end = System.currentTimeMillis();
XxlJobHelper.log("###### Job执行完成,耗时: {} 秒 ######",(end-start)/1000);
return ReturnT.SUCCESS;
}
public void bxCacheHandle(Date startTime, Date endTime) {
/**
* 伪代码,不能泄密,单纯打印看效果
*/
XxlJobHelper.log("{} {}-{} {} ", "bxCacheTableTask",startTime.toString(),endTime.toString(),"查询缓存数据...");
XxlJobHelper.log("{} 插入数据 ", "bxCacheTableTask");
}
public void bwmCacheHandle(Date startTime, Date endTime) {
/**
* 伪代码,不能泄密,单纯打印看效果
*/
XxlJobHelper.log("{} {}-{} {} ", "bwmCacheTableTask",startTime.toString(),endTime.toString(),"查询缓存数据...");
XxlJobHelper.log("{} 插入数据 ", "bwmCacheTableTask");
}
}
???????这些代码都是复用的,除了bxCacheHandle(beginTime,endTime);
是处理对应缓存表的逻辑代码,当我需要创建新的缓存表时,我都会把上面的代码复制下来修改@XxlJob("执行名称")
,在把bxCacheHandle(beginTime,endTime);
修改成对应缓存表查询处理的逻辑,而且他们共同点就是传入的参数都是开始时间和结束时间
,并且没有返回值,那么我们就可以使用BiConsumer<T, U>函数式接口来解决
.
???????其实除了时间范围内进行查询,我们还有用到按照传入的时间范围,在按照一天一天维度进行查询,这样的效果就是有些报表一次性查询范围30天会比较久,而且数据库的压力也会提升,我们就需要按照模式去选择,一次性查询一个月还是一个月分30次一天一天的去查询数据.
?? 函数编程简化
我们创建一个专门处理时间查询的类
/**
* @Author itmei
* @Date 2023/12/23 14:27
* @description: 时间范围处理
* @Title: DateQueryHandle
* @Package com.itmei.xxl.task
*/
public class DateQueryHandle {
/**
* 执行
* @param syncLogic 是一个函数式接口 BiConsumer<Date, Date> 的实例,用于执行具体的逻辑。该函数式接口接受两个 Date 类型的参数,分别表示开始时间和结束时间
* @param queryType true 一天一天查询 , false 日期区间查询
*/
public static void execute(BiConsumer<Date,Date> syncLogic,Boolean queryType){
long start = System.currentTimeMillis();
//获取xxl-job调度传递过来的数据
String param = XxlJobHelper.getJobParam();
XxlJobHelper.log("###### Job参数 ######\n{}",param);
XxlJobParam jobParam;
if (ObjectUtil.isNotEmpty(param)) {
jobParam = JSONUtil.toBean(param, XxlJobParam.class);
} else {
jobParam = new XxlJobParam();
}
DateTime beginTime;
DateTime endTime;
if (ObjectUtil.isEmpty(jobParam.getBeginTime()) || ObjectUtil.isEmpty(jobParam.getEndTime())) {
DateTime startDateTime;
DateTime endDateTime = DateUtil.date();
Integer beforeDays = jobParam.getBeforeDays();
if (ObjectUtil.isEmpty(beforeDays)) {
//默认开始时间是当前时间向之前偏移46天
startDateTime = DateUtil.offsetDay(new Date(), -46);
} else {
startDateTime = DateUtil.offsetDay(new Date(), -Integer.valueOf(beforeDays));
}
beginTime = DateUtil.beginOfDay(startDateTime);
endTime = DateUtil.endOfDay(endDateTime);
} else {
//处理时间范围
beginTime = DateUtil.beginOfDay(jobParam.getBeginTime());
endTime = DateUtil.endOfDay(jobParam.getEndTime());
}
if (queryType) {
// 按天查询
long days = DateUtil.between(beginTime, endTime, DateUnit.DAY);
for (int i = 0; i <= days; i++) {
DateTime dateTime = DateUtil.offsetDay(beginTime, i);
DateTime begin = DateUtil.beginOfDay(dateTime);
DateTime end = DateUtil.endOfDay(dateTime);
//调用传入的函数式接口实例的方法来执行具体的逻辑
syncLogic.accept(begin, end);
}
} else {
//调用传入的函数式接口实例的方法来执行具体的逻辑
syncLogic.accept(beginTime, endTime);
}
long end = System.currentTimeMillis();
XxlJobHelper.log("###### Job执行完成,耗时: {} 秒 ######",(end-start)/1000);
}
/**
* 执行
* @param syncLogic
*/
public static void execute(BiConsumer<Date,Date> syncLogic){
//重载方法 使用时间范围内的查询
execute(syncLogic,false);
}
}
🎄 JDK自带的函数式接口
???????唯一不一样的是使用了 JDK 1.8 中函数式接口BiConsumer
,这个接口默认可以传递2个参数.除了这个JDK 1.8 中还提供了这些常用的函数式接口:
Consumer<T>:接受一个输入参数 T,没有返回值。
Supplier<T>:不接受任何输入参数,返回一个结果 T。
Function<T, R>:接受一个输入参数 T,返回一个结果 R。
Predicate<T>:接受一个输入参数 T,返回一个布尔值。
UnaryOperator<T>:接受一个输入参数 T,返回一个结果 T,输入类型和返回类型相同。
BinaryOperator<T>:接受两个输入参数 T,返回一个结果 T,输入类型和返回类型相同。
BiConsumer<T, U>:接受两个输入参数 T 和 U,没有返回值。
BiFunction<T, U, R>:接受两个输入参数 T 和 U,返回一个结果 R。
BiPredicate<T, U>:接受两个输入参数 T 和 U,返回一个布尔值。
???????由于我们简化的代码中并没有返回值,而且需要传入2个参数,这样我们就选择了BiConsumer<T, U>
做为本次使用到的函数式接口.
? 改造调用方式
🎊 时间范围执行
我们改造
bwmCacheTableTask
代码,改成函数式接口方式调用
运行结果
改造后,我们只需要一行代码就可以,完成了代码的复用性
改造后的运行结果和改造前运行结果是一样的,这样是不是代码就更简化
🎉时间范围每天执行
改造
bxCacheTableTask
代码为,时间范围内,一天一天的执行效果
执行效果
按照时间范围内,进行一天一天查询
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!