SpringCloud升级之路2020.0.x版-37. 实现异步的客户端封装配置管理的意义与设计

为何需要封装异步 HTTP 客户端 WebClient
对于同步的请求,我们使用 spring-cloud-openfeign 封装的 FeignClient,并做了额外的定制。对于异步的请求,使用的是异步 Http 客户端即 WebClient。WebClient 使用也比较简单,举一个简单的例子即:
//使用 WebClient 的 Builder 创建 WebClient
WebClient client = WebClient.builder()
//指定基址
.baseUrl("http://httpbin.org")
//可以指定一些默认的参数,例如默认 Cookie,默认 HttpHeader 等等
.defaultCookie("cookieKey", "cookieValue")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
创建好 WebClient 后即可以使用这个 WebClient 进行调用:
// GET 请求 /anything 并将 body 转化为 String
Mono<String> stringMono = client.get().uri("/anything").retrieve().bodyToMono(String.class);
//这里为了测试,采用阻塞获取
String block = stringMono.block();
返回的结果如下所示(请求 http://httporg.bin/anything 会将请求中的所有内容原封不动返回,从这里我们可以看出上面测试的 Header 还有 cokkie 都被返回了):
{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip",
"Cookie": "TestCookie=TestCookieValue,getAnythingCookie=getAnythingCookieValue",
"Getanythingheader": "getAnythingHeaderValue",
"Host": "httpbin.org",
"Testheader": "TestHeaderValue",
"User-Agent": "ReactorNetty/1.0.7"
},
"json": null,
"method": "GET",
"origin": "12.12.12.12",
"url": "http://httpbin.org/anything"
}
我们也可以加入负载均衡的功能,让 WebClient 利用我们内部的 LoadBalancer,负载均衡调用其他微服务,首先注入负载均衡 Filter:
@Autowired
ReactorLoadBalancerExchangeFilterFunction lbFunction;
创建 WebClient 的时候,将这个 Filter 加入:
//使用 WebClient 的 Builder 创建 WebClient
WebClient client = WebClient.builder()
//指定基址微服务
.baseUrl("http://微服务名称")
//可以指定一些默认的参数,例如默认 Cookie,默认 HttpHeader 等等
.defaultCookie("cookieKey", "cookieValue")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
//负载均衡器,改写url
.filter(lbFunction)
.build();
这样,这个 WebClient 就能调用微服务了。
但是,这样还不能满足我们的需求:
- 需要在 WebClient 加入像 Feignclient 里面加的类似的重试与断路机制,线程隔离就不需要了,因为都是异步请求不会阻塞任务线程。
- 需要针对不同的微服务配置不同的连接超时以及响应超时来适应不同微服务。
- 这些配置都增加了代码的复杂度,我们需要减少这些代码对于业务的侵入性,最好能通过纯配置实现这些 WebClient 的初始化。
要实现的配置设计以及使用举例
首先,我们要实现的 WebClient,其 Filter 包含三个:
- 重试 Filter:重试的 Filter 要在负载均衡 Filter 之前,因为重试的时候,我们会从负载均衡器获取另一个实例进行重试,而不是在同一个实例上重试多次。
- 负载均衡 Filter,其实就是内置的
ReactorLoadBalancerExchangeFilterFunction - 断路器 Filter:断路器需要在负载均衡之后,因为只有负载均衡之后才能拿到具体本地调用的服务实例,这样我们才能实现基于微服务实例方法级别的断路器。
需要重试的场景:
- 非 2xx 的响应码返回,并且方法是可以重试的方法。如何定义方法是可以重试的,首先 GET 方法是可以重试的,对于其他方法,根据配置中的是否配置了这个 URL 可以重试决定。
- 异常重试:
- 连接异常:例如连接超时,连接中断等等,所有请求的连接异常都可以重试,因为请求并没有发出去。
- 断路器异常:该服务实例方法级别的断路器打开了,需要直接重试其他实例,因为请求并没有发出去。
- 响应超时异常:这个重试逻辑和非 2xx 的响应码返回一样。
我们需要实现的配置方式是,通过这样配置 application.yml:
webclient:
configs:
//微服务名称
testService1:
//请求基址,第一级域名作为微服务名称
baseUrl: http://testService1
//最多的 http 连接数量
maxConnection: 50
//连接超时
connectTimeout: 500ms
//响应超时
responseTimeout: 60s
//除了 GET 方法外,哪些路径还能重试
retryablePaths:
- /retryable/**
- /user/orders
加入这些配置,我们就能获取载对应微服务的 WebClient 的 Bean,例如:
//自动装载 我们自定义的 WebClient 的 NamedContextFactory,这个是我们后面要实现的
@Autowired
private WebClientNamedContextFactory webClientNamedContextFactory;
//通过微服务名称,获取对应的微服务调用的 WebClient
webClientNamedContextFactory.getWebClient("testService1");
接下来,我们会实现这些。
微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer:

SpringCloud升级之路2020.0.x版-37. 实现异步的客户端封装配置管理的意义与设计的更多相关文章
- SpringCloud升级之路2020.0.x版-18.Eureka的客户端核心设计和配置
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford Eureka 客户 ...
- SpringCloud升级之路2020.0.x版-1.背景
本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ Spring ...
- SpringCloud升级之路2020.0.x版-41. SpringCloudGateway 基本流程讲解(1)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 接下来,将进入我们升级之路的又一大模块,即网关模块.网关模块我们废弃了已经进入维护状态的 ...
- SpringCloud升级之路2020.0.x版-6.微服务特性相关的依赖说明
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford spring-cl ...
- SpringCloud升级之路2020.0.x版-10.使用Log4j2以及一些核心配置
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Log4 ...
- SpringCloud升级之路2020.0.x版-43.为何 SpringCloudGateway 中会有链路信息丢失
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在开始编写我们自己的日志 Filter 之前,还有一个问题我想在这里和大家分享,即在 Sp ...
- SpringCloud升级之路2020.0.x版-21.Spring Cloud LoadBalancer简介
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Spri ...
- SpringCloud升级之路2020.0.x版-29.Spring Cloud OpenFeign 的解析(1)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在使用云原生的很多微服务中,比较小规模的可能直接依靠云服务中的负载均衡器进行内部域名与服务 ...
- SpringCloud升级之路2020.0.x版-34.验证重试配置正确性(1)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面一节,我们利用 resilience4j 粘合了 OpenFeign 实现了断路器. ...
随机推荐
- DDD领域驱动设计落地实践(十分钟看完,半小时落地)
一.引子 不知今年吹了什么风,忽然DDD领域驱动设计进入大家视野.该思想源于2003年 Eric Evans编写的"Domain-Driven Design领域驱动设计"简称DDD ...
- 干货分享之Spring框架源码解析01-(xml配置解析)
记录并分享一下本人学习spring源码的过程,有什么问题或者补充会持续更新.欢迎大家指正! 环境: spring5.X + idea Spring 是一个工厂,是一个负责对象的创建和维护的工厂.它给我 ...
- 题解 「BZOJ2178」圆的面积并
题目传送门 题目大意 给出 \(n\) 个圆,求它们并的面积大小. \(n\le 10^3\) 思路 如果您不会自适应辛普森法,请戳这里学习 其实我们发现,如果我们设 \(f(x)\) 表示 \(x= ...
- 多项式(polynomial)
多项式(polynomial) 题目大意: 给出一个 n 次多项式 \(f(x)=\sum_{i=0}^na_ix^i\) 对于\(k ≤ x ≤ k + l − 1\) 的\(l\) 个\(x\), ...
- 面试官:Java从编译到执行,发生了什么?
面试官:今天从基础先问起吧,你是怎么理解Java是一门「跨平台」的语言,也就是「一次编译,到处运行的」? 候选者:很好理解啊,因为我们有JVM. 候选者:Java源代码会被编译为class文件,cla ...
- Golang通脉之数组
数组是同一种数据类型元素的集合.数组在内存中都是连续存放的. 在Go语言中,数组从声明时就确定,使用时可以修改数组成员,但是数组大小不可变化. 基本语法: // 定义一个长度为3元素类型为int的数组 ...
- [敏捷软工团队博客]Beta阶段测试报告
项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta阶段测试报告 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Bet ...
- (数据科学学习手札129)geopandas 0.10版本重要新特性一览
本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在前不久,我们非常熟悉的Python地理 ...
- elasticsearch父子文档处理(join)
elasticsearch父子文档处理 join 一.背景 二.需求 三.前置知识 四.实现步骤 1.创建 mapping 2.添加父文档数据 3.添加子文档 4.查询文档 1.根据父文档id查询它下 ...
- flink中使用lambda表达式
flink中使用lambda表达式 1.使用lambda的一个示例 2.使用上面这种写法通常或得到如下错误 3.解决方案 4.建议 5.完整代码 在 java8中有一种新的语法糖,即 lambda表达 ...