电商项目之Java8函数式接口落地实践

在这里插入图片描述

文章目录

  • 1 问题背景
  • 2 前言
  • 3 多处重复的重试机制代码
  • 4 优化后的代码
  • 5 进一步优化

1 问题背景

在电商场景中,会调用很多第三方的云服务,比如发送邮件、发起支付、发送验证码等等。由于网络存在抖动,有时候发起调用后会拿到500的状态码,io exception等报错,因此需要重新调用,简称重试机制。项目中很多地方用到重试机制,导致很多重复的代码,因此笔者考虑使用Java8函数式接口优化该重试机制,抽成一个工具类方法。

2 前言

  1. 本文的代码中,可能有些类型没有给出代码,不需要纠结,主要了解函数式接口怎么应用即可

3 多处重复的重试机制代码

项目中多次出现的代码如下:

        BasicResponse<String> response = null;int retryTimes = 0;do {try {String startTimeStr = DATE_TIME_FORMATTER.format(LocalDateTime.now());response = restTemplate.postForString(basicRequest); // 此行代码是可变的,可能是get方式请求,可能是post方式String endTimeStr = DATE_TIME_FORMATTER.format(LocalDateTime.now());PayReq logObject = PayReq.getLogObject(payReq);log.info("XXXPay payOrder, request:{}, response:{}, startTimeStr:{}, endTimeStr:{}, retryTimes:{}", JSON.toJSONString(logObject), JSON.toJSONString(response), startTimeStr, endTimeStr, retryTimes);} finally {if (response != null && !response.getCode().equals(HttpStatus.SC_OK)) {try {Thread.sleep(500L);} catch (InterruptedException e) {e.printStackTrace();}}retryTimes++;}} while (!response.getCode().equals(HttpStatus.SC_OK) && retryTimes < 3);

分析:

如上所示,在这行代码response = restTemplate.postForString(basicRequest);是可变的,有可能是get方式提交http请求,有可能是post方式。因此要把此处抽象出来,交给调用者写具体实现。调用者需要拿到http响应报文,那么抽象出来的接口,需要有返回值。那么此处可以使用Supplier函数式接口,或者自己定义一个有返回值的函数式接口也可以。

log.info打日志这行,需要打出响应报文、开始时间、结束时间、重试次数等,这些都可以抽到工具类里面,但是日志的内容XXXPay payOrder这些是可变的,应该交由调用者写具体实现。那么我们可以定义一个函数式接口出来,有入参但无返回值,入参是提供给调用者使用的。

4 优化后的代码

定义一个打日志的函数式接口:

/*** 打日志的函数式接口* * @param <T>*/
@FunctionalInterface
public interface LogFunc<T> {/*** 打日志* * @param response 响应报文* @param startTimeStr http调用开始时间* @param endTimeStr http调用结束时间* @param curTime 当前重试次数*/void log(T response,  String startTimeStr, String endTimeStr, int curTime);
}

Http重试工具类如下,主要关注有代码注释的那两处地方即可:

@Slf4j
public class HttpRetryUtil {private final static DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS");public static <T> T retryOnException(Supplier<T> supplier, LogFunc logFunc,int maxRetryTimes, long sleepMillis) {T result = null;int retryTimes = 0;do {try {String startTimeStr = LocalDateTime.now().format(DATE_TIME_FORMATTER);// 交给调用者写具体实现,并把值返回出去result = supplier.get();String endTimeStr = LocalDateTime.now().format(DATE_TIME_FORMATTER);// 交给调用者写具体实现,入参供调用者使用logFunc.log(result, startTimeStr, endTimeStr, retryTimes);} catch (Exception e) {e.printStackTrace();} finally {if (result != null && !((BasicResponse<String>) result).getCode().equals(HttpStatus.SC_OK)) {try {Thread.sleep(sleepMillis);} catch (InterruptedException e) {e.printStackTrace();}}retryTimes++;}} while (((result == null) || !((BasicResponse<String>) result).getCode().equals(HttpStatus.SC_OK))&& retryTimes < maxRetryTimes);return result;}
}

测试用例,如下所示,优化前有21行/代码(见第3小节的代码),其实如果不写注释不换行,只需用1行就可以将这个重试机制调用起来了(见下面的代码),简洁多了:

@Slf4j
public class HttpRetryUtilTest extends AppTest {@Resourceprivate HttpRestTemplate restTemplate;@Testpublic void testRetry(){BasicRequest basicRequest = new BasicRequest();basicRequest.setMethodUrl("https://www.google.com");BasicResponse<String> resp = HttpRetryUtil.retryOnException(// 实现supplier函数式接口() -> restTemplate.getForString(basicRequest), // 实现LogFunc函数式接口(response, startTimeStr, endTimeStr, curTime) -> log.info("HttpRetryUtil retryOnException, request:{}, response:{}, startTimeStr:{}, endTimeStr:{}, times:{}", JSON.toJSONString(basicRequest), JSON.toJSONString(response), startTimeStr, endTimeStr, curTime), 3, 500L);log.info("repsonse:{}", JSON.toJSONString(resp));}
}

5 进一步优化

针对那些重试次数、休眠时间,可以在工具类中再定义一些默认的重试次数、默认的休眠时间,然后利用Java的多态特性(方法重载)定义多种工具方法即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/186647.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux学习第38天:Linux I2C 驱动实验(二):哥俩好

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本节笔记主要学习I2C设备驱动编写及硬件原理图分析。 先把整个本节的思维导图贴出来&#xff1a; 二、I.MX6U的I2C适配器驱动分析 适配器驱动一般都是由SOC厂商提…

最新整理【剑侠情缘龙雀修复BGU版】linux服务端带授权后台+详细教程+包进游戏

搭建资源下载地址&#xff1a;最新整理【剑侠情缘龙雀修复BGU版】linux服务端带授权后台详细教程包进游戏 - 海盗空间

虚幻5 删除C盘缓存及修改缓存路径

一.修改C盘缓存 C盘缓存路径为&#xff1a; C:\Users\xx(这里是你的用户名)\AppData\Local\UnrealEngine\Common\DerivedDataCache 注意&#xff0c;如果没有AppData文件夹&#xff0c;请依次点击查看-勾选显示隐藏的项目&#xff0c;即可 可删除里面的所有文件即可 二.修改…

nanodet训练自己的数据集、NCNN部署到Android

nanodet训练自己的数据集、NCNN部署到Android 一、介绍二、训练自己的数据集1. 运行环境2. 数据集3. 配置文件4. 训练5. 训练可视化6. 测试 三、部署到android1. 使用官方权重文件部署1.1 下载权重文件1.2 使用Android Studio部署apk 2. 部署自己的模型【暂时存在问题】2.1 生成…

Win10 + VS017 编译SQLite3.12.2源码

参考&#xff1a; [1] WIN10 VS2019下编译GDAL3.0PROJ6SQLite_gdal 3 win10编译-CSDN博客 [2] 如何编译SQLite-How To Compile SQLite-CSDN博客 如何生成静态库&#xff1a; 参考&#xff1a; WIN10 VS2019下编译GDAL3.0PROJ6SQLite_gdal 3 win10编译-CSDN博客 如何生成exe:…

105.am40刷机(linux)折腾记1-前期的准备工作1

前段时间在某鱼上逛的时候&#xff0c;发现一款3399的盒子只要150大洋&#xff0c;内心就开始澎拜&#xff0c;一激动就下手了3台&#xff0c;花了450大洋&#xff08;现在想想&#xff0c;心都碎了一地&#xff09;。 然后自己又来来回回折腾了几天&#xff0c;目前能跑上fire…

viple入门(四)

&#xff08;1&#xff09;行打印 主要用于在运行窗口中显示数据&#xff0c;打印完成后&#xff0c;自动换行。 注意事项&#xff1a;不可同时打印两个数据&#xff0c;例如 解决方案1&#xff1a;使用或并&#xff0c;使得每次进入行打印的数据只有一个&#xff0c;缺点&am…

2020年五一杯数学建模B题基于系统性风险角度的基金资产配置策略分析解题全过程文档及程序

2020年五一杯数学建模 B题 基于系统性风险角度的基金资产配置策略分析 原题再现 近年来&#xff0c;随着改革开放程度的不断提高&#xff0c;我国经济运行中的各种风险逐渐暴露并集中传导和体现于金融领域。党的“十九大”报告提出“守住不发生系统性金融风险的底线”要求&am…

「Verilog学习笔记」4位数值比较器电路

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 这里要注意题目的“门级描述方式”&#xff0c;所以我们只能使用基本门电路&#xff1a;&,|,!,^,^~。 具体实现思路&#xff1a;通过真值表得出Y0 Y1 Y2的逻辑表达…

前端AJAX入门到实战,学习前端框架前必会的(ajax+node.js+webpack+git)(三)

知者乐水&#xff0c;仁者乐山。 XMLHttpRequest AJAX原理 - XMLHttpRequest 前面与服务器交互使用的不是axios吗&#xff1f; ajax并不等于axios 我们使用的axios的内部&#xff0c;实际上对XHR对象/原理 的封装 为什么还要学习ajax&#xff1f; ①在一些静态网站项目中…

rabbitMq虚拟主机概念

虚拟主机是RabbitMQ中的一种逻辑隔离机制&#xff0c;用于将消息队列、交换机以及其他相关资源进行隔离。 在RabbitMQ中&#xff0c;交换机&#xff08;Exchange&#xff09;用于接收生产者发送的消息&#xff0c;并根据特定的路由规则将消息分发到相应的队列中。而虚拟主机则…

矩阵起源荣获第八届“创客中国”深圳市中小企业创新创业大赛三等奖

近日&#xff0c;2023年第八届“创客中国”深圳市中小企业创新创业大赛圆满落下帷幕&#xff0c;矩阵起源&#xff08;深圳&#xff09;信息科技有限公司凭借项目”MatrixOne 新一代超融合异构云原生数据库”荣获企业组三等奖。 本届大赛由深圳市工业和信息化局、深圳市中小企业…

Vue入门教学——编写第一个页面

以Vue2.0为例子。 1、创建一个Vue项目 创建过程&#xff1a;Vue-cli&#xff08;脚手架&#xff09;的创建_vue脚手架创建项目命令-CSDN博客【注】项目名不能有大写字母。创建完毕后&#xff0c;使用VSCode打开项目文件夹&#xff08;其他编辑器也行&#xff09;。 2、运行项…

震裕科技-300953 三季报分析(20231108)

震裕科技-300953 基本情况 公司名称&#xff1a;宁波震裕科技股份有限公司 A股简称&#xff1a;震裕科技 成立日期&#xff1a;1994-10-18 上市日期&#xff1a;2021-03-18 所属行业&#xff1a;专用设备制造业 周期性&#xff1a;0 主营业务&#xff1a;精密级进冲压模具及下游…

【C语言 | 预处理】C语言预处理详解(二) —— #pragma指令介绍以及内存对齐、结构体大小

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

vite + electron引入itk报错

代码 import { readImageArrayBuffer } from itk-wasm console.log(readImageArrayBuffer)通过itk-wasm官网&#xff0c;创建新的项目vitevue&#xff08;vue2或者vue3&#xff09;&#xff0c;都没问题。加入electeon后包此错。通过排查&#xff0c;意外找到原因&#xff0c;…

直面LED Driver测试挑战,助力显示屏行业变中求变!

杭州亚运会开幕式惊艳世界&#xff0c;引发社会各界一致赞誉&#xff01;在大气浪漫的舞台效果中&#xff0c;LED屏、裸眼3D屏凭借“硬核科技”出圈&#xff0c;为大家带来科技、活力、诗意的“中国式浪漫”观赏体验。而这美轮美奂的LED呈现效果背后&#xff0c;主要依靠的是LE…

企业安全—三保一评

0x00 前言 本篇主要是讲解三保一评的基础知识&#xff0c;以及对为什么要进行这些内容的原因进行总结。 0x01 整体 1.概述 三保分别是&#xff0c;分保&#xff0c;等保&#xff0c;关保。 分保就是指涉密信息系统的建设使用单位根据分级保护管理办法和有关标准&#xff0c…

修改Android Studio默认的gradle目录

今天看了一下&#xff0c;gradle在C盘占用了40多G。我C盘是做GHOST的&#xff0c;放在这里不方便。所以就要修改。 新建目录名&#xff08;似乎无必要&#xff09; ANDROID_SDK_HOMEG:\SOFTWARES\android-sdk GRADLE_USER_HOMEG:\SOFTWARES\.gradle 修改目录 File->Setti…

【Cocos新手进阶】父级预制体中的数据列表,在子预制体中的控制方法!

本篇文章主要讲解&#xff0c;cocos中在预制体操作过程中&#xff0c;父级预制体生成的数据列表中&#xff0c;绑定了子预制体中的事件&#xff0c;在子预制体的时间中如何控制上级列表的具体操作教程。 日期&#xff1a;2023年11月10日 作者&#xff1a;任聪聪 一、实际效果情…