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

干货满满张哈希 等级 60 0 0

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

本系列代码地址: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. 实现异步的客户端封装配置管理的意义与设计

收藏
评论区

相关推荐

JAVA回调机制(CallBack)之小红是怎样买到房子的??
JAVA回调机制CallBack 序言最近学习java,接触到了回调机制(CallBack)。初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义。当然了,我在理解了回调之后,再去看网上的各种讲解,确实没什么问题。但是,对于初学的我来说,缺了一个循序渐进的过程。此处,将我对回调机制的个人理解,按
SpringCloud升级之路2020.0.x版-19.Eureka的服务端设计与配置
本系列代码地址:https://github.com/HashZhang/springcloudscaffold/tree/master/springcloudiifordEureka Server 配置是 Eureka Server 需要的一些配置,包括之前多次提到的定时检查实例过期的配置,自我保护相关的配置,同一 zone 内集群相关的配置和跨 zone
SpringCloud升级之路2020.0.x版-26.OpenFeign的组件
本系列代码地址:https://github.com/JoJoTec/springcloudparent首先,我们给出官方文档中的组件结构图:官方文档中的组件,是以实现功能为维度的,我们这里是以源码实现为维度的(因为之后我们使用的时候,需要根据需要定制这些组件,所以需要从源码角度去拆分分析),可能会有一些小差异。 负责解析类元数据的 ContractOpen
2021升级版微服务教程5—通过IDEA运行多个项目实例「模拟集群」
2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 ![](https://oscimg.oschina.net/oscnet/c90af336-21f6-4812-a448-cdce3e5d903a.png) **教程全目录「含视频」**:https://gitee.com/bingqilinpe
2021升级版微服务教程4—Nacos 服务注册和发现
2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 ![](https://oscimg.oschina.net/oscnet/f2a7c1f4-d28b-48a9-b156-11d0a33ad613.png) 默认文件1610014380163 **教程全目录「含视频」**:https://gi
2021升级版微服务教程4—Nacos 服务注册和发现
2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 ![](https://oscimg.oschina.net/oscnet/f2a7c1f4-d28b-48a9-b156-11d0a33ad613.png) 默认文件1610014380163 **教程全目录「含视频」**:https://gi
Debug与Release版本的区别
Debug 和 Release 并没有本质的区别,他们只是VC预定义提供的两组编译选项的集合,编译器只是按照预定的选项行动。如果我们愿意,我们完全可以把Debug和Release的行为完全颠倒过来。当然也可以提供其他的模式,例如自己定义一组编译选项,然后命名为MY\_ABC等。习惯上,我们仍然更愿意使用VC已经定义好的名称。 Debug版本包括调试信
Spring Cloud Config Server迁移节点或容器化带来的问题 原因,解决
版本 == * springboot 2.0.1.RELEASE * springcloud Finchley.RC1 问题 == 看程序猿 dd 的博客 [http://blog.didispace.com/Spring-Cloud-Config-Server-ip-change-problem/](https://www.oschina.n
Spring Cloud系列教程(六):服务注册与发现Consul(Finchley版本)
一、前言 ---- 在微服务领域,服务注册与发现是其中很重要的一个模块,主要用于服务治理问题;在分布式`Dubbo`中常用的服务发现与注册中心是`Zookeeper`,`Cosul`与其类似,在`SpringCloud`刚占领市场的时候,`SpringCloud`微服务框架默认使用的注册中心组建是`Eureka`,总所周知,`Eureka`已经开始闭源了,
SpringBoot与SpringCloud的版本对应详细版
大版本对应: Spring Boot Spring Cloud 1.2.x Angel版本 1.3.x Brixton版本 1.4.x stripes Camden版本 1.5.x Dalston版本、Edgware版本 2.0.x Finchley版本 2.1.x Greenwich.SR2 在实际开发过程中,我们需要更**详
SpringBoot与SpringCloud的版本对应详细版
大版本对应: Spring Boot Spring Cloud 1.2.x Angel版本 1.3.x Brixton版本 1.4.x stripes Camden版本 1.5.x Dalston版本、Edgware版本 2.0.x Finchley版本 2.1.x Greenwich.SR2 在实际开发过程中,我们需要更**详
SpringCloud Alibaba微服务实战十六
点击上方 蓝字 关注我们 概述 -- 好久没有更新SpringCloud Alibaba 系列的文章了,今天我们来将版本升级到最新的毕业版本。并且将原来容器化部署的组件seata、nacos、sentinel拉出来单独部署,为我们后面k8s部署作准备。 官方推荐版本如下:![](https://oscimg.oschina.net/oscnet/e7f
SpringCloud demo
1.首先创建一个maven项目 ===============   这个maven项目会包含springcloud相关的项目,目录结构如下图:     本项目所有的springcloud版本为Finchley.SR2,对应的springboot的版本为2.0.7.RELEASE。     ![](https://img2018.cnblogs.com/
SpringCloud的版本
Spring Cloud 项目目前仍然是快速迭代期,版本变化很快。这里整理一下版本相关的东西,备忘一下。 大版本 --- ### 版本号规则 Spring Cloud并没有熟悉的数字版本号,而是对应一个开发代号。 Cloud代号 Boot版本(train) Boot版本(tested) lifecycle Angle 1.2.x inco
springcloud知识点总结
一.SpringCloud面试题口述 1.SpringCloud和Dubbo SpringCloud和Dubbo都是现在主流的微服务架构 SpringCloud是Apache旗下的Spring体系下的微服务解决方案 Dubbo是阿里系的分布式服务治理框架 从技术维度上,其实SpringCloud远远的超过Dubbo,Dubbo本身只是实现