电商项目之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.mzph.cn/news/136569.shtml

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

相关文章

C现代方法(第19章)笔记——程序设计

文章目录 第19章 程序设计19.1 模块19.1.1 内聚性与耦合性19.1.2 模块的类型 19.2 信息隐藏19.2.1 栈模块 19.3 抽象数据类型19.3.1 封装19.3.2 不完整类型 19.4 栈抽象数据类型19.4.1 为栈抽象数据类型定义接口19.4.2 用定长数组实现栈抽象数据类型19.4.3 改变栈抽象数据类型中…

Code Review最佳实践

Code Review最佳实践 Code Review 我一直认为Code Review&#xff08;代码审查&#xff09;是软件开发中的最佳实践之一&#xff0c;可以有效提高整体代码质量&#xff0c;及时发现代码中可能存在的问题。包括像Google、微软这些公司&#xff0c;Code Review都是基本要求&…

Hive的时间操作函数

目录 前言函数使用介绍实际使用判断该天是星期几判断该天对应的周&#xff08;包含一周开始和结束&#xff09; 前言 hive 里面的时间函数有很多&#xff0c;今天单讲dayofweek函数&#xff0c;背景&#xff1a;有时候不仅要出日报&#xff0c;还要出周报&#xff0c;需要很多…

uniapp 下载文件到手机

下载后端传递过来的文件 let thil this uni.showLoading({title: 下载中,mask:true }) uni.downloadFile({url: 接口地址, //仅为示例&#xff0c;并非真实的资源header: {"Authorization": token},responseType: blob,success: (res) > {if (res.statusCode 2…

什么是网络爬虫?

网络爬虫是一种自动化程序&#xff0c;可以自动地浏览网站并从网站上抽取数据。APP数据抓取实际上也是运用了网络爬虫的技术&#xff0c;只不过抓取的对象不是网站上的信息&#xff0c;而是手机APP上的数据。下面详细介绍APP数据抓取的过程。 1、确定数据需求 首先需要明确要抓…

【数据结构】树与二叉树(七):二叉树的遍历

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语5.1.4 树的表示 5.2 二叉树5.2.1 二叉树1. 定义2. 特点3. 性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉…

代挂单页网址发布页+加盟代理+APP下载页源码

代挂单页加盟代理网址发布页app下载页HTML单页版本&#xff0c;自行修改源码内文字。自行修改联系方式、登录地址&#xff01;上传即可使用。源码我已全部打包好&#xff0c;直接上传本站提供的源码&#xff0c;无后台&#xff0c;直接访问即可&#xff01; 源码下载&#xff…

EF Core 数据库映射成实体类

首先在 NuGet 包管理器中安装三个包 Microsoft.EntityFrameworkCore.SqlServer 是一个用于与 SQL Server 数据库进行交互的实体框架核心包。这个包提供了方便的方法和工具&#xff0c;用于在 .NET Core 应用程序中操作 SQL Server 数据库。 Microsoft.EntityFrameworkCore.Too…

fmx windows 下 制作无边框窗口最小化最大化并鼠标可拖移窗口

1,最顶端 放一个rectangle 置顶 ,此区域后面实现鼠标拖动 移动窗口,可在上面放置最大,最小,关闭按钮 2,窗口边框模式 设置 none 3,rectangel mousemove事件 uses Winapi.Windows,Winapi.Messages,FMX.Platform.Winprocedure TfrmMain.Rectangle1MouseMove(Sender: TObje…

[直播自学]-[汇川easy320]搞起来(3)看文档安装软件 查找设备

2023.11.09 20&#xff1a;04 按照文档 解压压缩包得到&#xff1a; 打开 里面有一条值得注意&#xff1a; 想把软件安装到C盘&#xff0c;但是C盘没什么空间了&#xff0c;把C盘清理清理。 20&#xff1a;35 安装很快完成&#xff0c;然后阅读 由于PLC是新的&#xff0c…

Postgresql数据类型-布尔类型

前面介绍了PostgreSQL支持的数字类型、字符类型、时间日期类型&#xff0c;这些数据类型是关系型数据库的常规数据类型&#xff0c;此外PostgreSQL还支持很多非常规数据类型&#xff0c;比如布尔类型、网络地址类型、数组类型、范围类型、json/jsonb类型等&#xff0c;从这一节…

Bean作用域

从笔者之前的博客&#xff0c;我们可以看出 Spring 是⽤来读取和存储 Bean&#xff0c;因此在 Spring 中 Bean 是最核⼼的操作 资源&#xff0c;所以接下来我们深⼊学习⼀下 Bean 对象&#xff1a;Bean作用域&#xff01; 限定程序中变量的可用范围叫做作用域&#xff01;或者…

三相桥式整流器设计与谐波分析

摘 要 三相桥式整流器应用广泛&#xff0c;比如电力系统、电机以及电子设备等行业。更高效率和更小体积的三相桥式整流器一直是研究的热点。在我们日常生活中&#xff0c; 三相桥式整流器随处可见&#xff0c;因为其相比其他整流器而言结构相对简单&#xff0c;运行稳定且便于…

scss 实用教程

变量 $ 定义变量 $link-color: blue;变量名可以与css中的属性名和选择器名称相同 使用变量 a {color: $link_color; }$highlight-border: 1px solid $link_color;中划线和下划线相互兼容&#xff0c;即中划线声明的变量可以使用下划线的方式引用&#xff0c;反之亦然。 $li…

5分钟Python安装实战(MAC版本)

最近在学习Chatgpt接口&#xff0c;官方提供三种方式调用Chatgpt接口&#xff0c;分别是curl、python、node.js&#xff1a;具体介绍我放在下方图片 因为熟悉Python&#xff0c;所以我选择了python这种方式&#xff0c;顺便记录下安装过程&#xff0c;整体并不复杂&#xff0c;…

npm 下载包失败解决方案

1.【问题描述】使用 npm 下载vue项目依赖包时失败&#xff0c;版本不一致。 【解决方法】使用 npm install --force npm install --force 是一个命令行指令&#xff0c;用于在 Node.js 环境中使用 npm&#xff08;Node Package Manager&#xff09;安装包或模块。–force 参数表…

python目标检测将视频按照帧率切除成图片

python目标检测将视频按照帧率切除成图片 python目标检测将视频按照帧率切除成图片&#xff0c;并且允许放入多个多个视频 完整代码如下&#xff1a; import os import cv2class VideoSplit:"""将视频分帧为图片source_path: 视频文件存储地址result_path&am…

单例模式 rust和java的实现

文章目录 单例模式介绍应用实例&#xff1a;优点使用场景 架构图JAVA 实现单例模式的几种实现方式 rust实现 rust代码仓库 单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是最简单的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建…

【Git企业开发】第六节.配置 Git和标签管理

文章目录 前言一、配置 Git 1.1 忽略特殊文件 1.2 给命令配置别名二、标签管理 2.1 理解标签 2.2 创建标签 2.3 操作标签 总结 前言 一、配置 Git 1.1 忽略特殊文件 在日常开发中&#xff0c;我们有些文件不想或者不应该提交到远端&#xff0c;…

Go语言函数用法

文章目录 Go语言函数用法 Go语言函数用法 函数在Go语言中有多种用法&#xff0c;它们是组织和模块化代码、提高代码的可维护性和可重用性的关键部分。以下是函数的一些常见用法&#xff1a; 封装代码&#xff1a;函数允许将一组相关的代码块封装到一个独立的单元中&#xff0c…