本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent

为何需要封装异步 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 就能调用微服务了。

但是,这样还不能满足我们的需求:

  1. 需要在 WebClient 加入像 Feignclient 里面加的类似的重试与断路机制,线程隔离就不需要了,因为都是异步请求不会阻塞任务线程。
  2. 需要针对不同的微服务配置不同的连接超时以及响应超时来适应不同微服务。
  3. 这些配置都增加了代码的复杂度,我们需要减少这些代码对于业务的侵入性,最好能通过纯配置实现这些 WebClient 的初始化。

要实现的配置设计以及使用举例

首先,我们要实现的 WebClient,其 Filter 包含三个:

  1. 重试 Filter:重试的 Filter 要在负载均衡 Filter 之前,因为重试的时候,我们会从负载均衡器获取另一个实例进行重试,而不是在同一个实例上重试多次
  2. 负载均衡 Filter,其实就是内置的 ReactorLoadBalancerExchangeFilterFunction
  3. 断路器 Filter:断路器需要在负载均衡之后,因为只有负载均衡之后才能拿到具体本地调用的服务实例,这样我们才能实现基于微服务实例方法级别的断路器

需要重试的场景:

  1. 非 2xx 的响应码返回,并且方法是可以重试的方法。如何定义方法是可以重试的,首先 GET 方法是可以重试的,对于其他方法,根据配置中的是否配置了这个 URL 可以重试决定
  2. 异常重试
    1. 连接异常:例如连接超时,连接中断等等,所有请求的连接异常都可以重试,因为请求并没有发出去。
    2. 断路器异常:该服务实例方法级别的断路器打开了,需要直接重试其他实例,因为请求并没有发出去。
    3. 响应超时异常:这个重试逻辑和非 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. 实现异步的客户端封装配置管理的意义与设计的更多相关文章

  1. SpringCloud升级之路2020.0.x版-18.Eureka的客户端核心设计和配置

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford Eureka 客户 ...

  2. SpringCloud升级之路2020.0.x版-1.背景

    本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ Spring ...

  3. SpringCloud升级之路2020.0.x版-41. SpringCloudGateway 基本流程讲解(1)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 接下来,将进入我们升级之路的又一大模块,即网关模块.网关模块我们废弃了已经进入维护状态的 ...

  4. SpringCloud升级之路2020.0.x版-6.微服务特性相关的依赖说明

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford spring-cl ...

  5. SpringCloud升级之路2020.0.x版-10.使用Log4j2以及一些核心配置

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Log4 ...

  6. SpringCloud升级之路2020.0.x版-43.为何 SpringCloudGateway 中会有链路信息丢失

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在开始编写我们自己的日志 Filter 之前,还有一个问题我想在这里和大家分享,即在 Sp ...

  7. SpringCloud升级之路2020.0.x版-21.Spring Cloud LoadBalancer简介

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Spri ...

  8. SpringCloud升级之路2020.0.x版-29.Spring Cloud OpenFeign 的解析(1)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在使用云原生的很多微服务中,比较小规模的可能直接依靠云服务中的负载均衡器进行内部域名与服务 ...

  9. SpringCloud升级之路2020.0.x版-34.验证重试配置正确性(1)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面一节,我们利用 resilience4j 粘合了 OpenFeign 实现了断路器. ...

随机推荐

  1. .NET跨平台实践:.NetCore、.Net5/6 Linux守护进程设计

    之前,我写过两篇关于用C#开发Linux守护进程的技术文章,分别是<.NET跨平台实践:用C#开发Linux守护进程>和<.NET跨平台实践:再谈用C#开发Linux守护进程 - 完 ...

  2. Vulnstack内网靶场1

    最近发现了一个内网的靶场网站,简单配置一下网络就可以,不用自己搭建这么麻烦漏洞信息 (qiyuanxuetang.net) 环境配置 内网1靶场由三台机器构成:WIN7.2008 server.200 ...

  3. VS Code环境配置

    1.语言配置 2.Node.js安装配置 系统变量中NODE_PATH,变量值为nodejs的安装路径. 用户变量Path包含%NODE_PATH% 如果说通过CMD打开的命令行可以执行node -v ...

  4. Idea进行java应用的远程调试Remote debugging

    本文可以解决如下两个问题: 1.如何处理和调试那些只发生在生产环境(或其他远程环境)而本地开发环境可能没办法重现的"问题". 2.只有一个可以部署的war/jar包,只有class ...

  5. 题解 [ZJOI2016]大森林

    题目传送门 Description 现在有 \(n\) 棵以 \(1\) 为根的树,每棵树有一个生长节点,有 \(m\) 次操作,每次操作是下面三种中的一个: 在 \(l\sim r\) 的这些树的生 ...

  6. 题解 「BJOI2018 治疗之雨」

    题目传送门 题目大意 有一个初始为 \(p\) 的数,每次操作分为以下两个: 有 \(\frac{1}{m+1}\) 的概率$+1,但是中途 \(p\) 的最大值只能为 \(n\)$ 有 \(k\) ...

  7. java中this关键字总结

    1.this是一个引用,也是一个变量,存储在JVM堆内存的Java对象内部. 2.this变量中保存的内存地址指向自身. 3.this可以在实例方法中使用,this指向当前正在执行这个动作的对象(th ...

  8. zlib开发笔记(四):zlib库介绍、编译windows vs2015x64版本和工程模板

    前言   Qt使用一些压缩解压功能,介绍过libzip库编译,本篇说明zlib库.需要用到zlib的msvc2015x64版本,编译一下.   版本编译引导 zlib在windows上的mingw32 ...

  9. [技术博客]WEB实现划词右键操作

    [技术博客]WEB实现划词右键操作 一.功能解释 简单地对题目中描述的功能进行解释:在浏览器中,通过拖动鼠标选中一个词(或一段文字),右键弹出菜单,且菜单为自定义菜单,而非浏览器本身的菜单.类似的功能 ...

  10. oo第四单元及期末总结

    一.第四单元作业架构总结 第一次UML作业: 在分析各指令所需要的信息后建立了类(class),操作(operation),属性(Attribute)这几个类用来存储分析后的结果,而接口在本次作业中与 ...