SpringCloud原理-OpenFeign篇(四、请求原理)

文章目录

  • 前言
  • 正文
    • 一、书接上回,从代理对象入手
    • 二、ReflectiveFeign.FeignInvocationHandler#invoke()
    • 三、SynchronousMethodHandler#invoke(...) 的实现原理
      • 3.1 invoke(...)源码
      • 3.2 executeAndDecode(...) 执行请求并解码
    • 四、如何更换client 的实现
  • 附录
    • 附1:本系列文章链接
    • 附2:比较HttpURLConnection、Apache HttpClient、OkHttp

前言

本篇是SpringCloud原理系列的 OpenFeign 模块的第四篇。

在我们启动完应用后,Spring容器也初始化好了很多我们用到的类。(什么,你不知道,烦请先看看第三篇)

那么我们下一步要做的就是,发出rest请求,然后调用FeignClient标注的接口方法。这篇文章,我们就来看看它的原理。

本文关键词:RequestTemplateSynchronousMethodHandler

使用java 17,spring cloud 4.0.4,springboot 3.1.4
使用项目是本系列第一篇中的项目

正文

一、书接上回,从代理对象入手

第三篇文章时,我们看到了SpringCloud将 OpenFeign的接口,映射为一个代理对象。
打个比方,使用如下接口:

@FeignClient(name = "helloFeignClient", url = "http://localhost:10080")
public interface HelloFeignClient {@PostMapping("/hello/post")HelloResponse postHello(@RequestBody HelloRequest helloRequest);
}

最终生成的代理对象是对 HelloFeignClient 接口的代理,并且绑定了handler。handler的类型是ReflectiveFeign.FeignInvocationHandler
在这里插入图片描述
换句话说,就是当我们调用接口HelloFeignClient 中的方法时,会触发调用ReflectiveFeign.FeignInvocationHandlerinvoke(...)方法。

二、ReflectiveFeign.FeignInvocationHandler#invoke()

在这里插入图片描述
查看源码可以知道,这里invoke方法,实际是先从 dispatch中找到对应方法的真正的处理器,然后进行调用。
从第三篇文章,我们能知道 dispatch 是对 method 的映射。

比如接口HelloFeignClient 会被映射为dispatch,一个方法对应为一对key、value值。dispatch的类型是:

private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;

也就是说Method 只是作为一个桥梁,连接起了HelloFeignClient 内的方法和真正执行的handler实例。这里的实例真正的实现是SynchronousMethodHandler。也就是说,当我们调用接口方法时,会执行SynchronousMethodHandler#invoke(...)

三、SynchronousMethodHandler#invoke(…) 的实现原理

3.1 invoke(…)源码

public Object invoke(Object[] argv) throws Throwable {// 创建请求模板,包装请求头、请求体,url等字段参数RequestTemplate template = this.buildTemplateFromArgs.create(argv);// 获取连接超时等参数Request.Options options = this.findOptions(argv);// 重试Retryer retryer = this.retryer.clone();while(true) {try {// 执行请求并解码return this.executeAndDecode(template, options);} catch (RetryableException var9) {RetryableException e = var9;try {retryer.continueOrPropagate(e);} catch (RetryableException var8) {Throwable cause = var8.getCause();if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {throw cause;}throw var8;}if (this.logLevel != Level.NONE) {this.logger.logRetry(this.metadata.configKey(), this.logLevel);}}}}

3.2 executeAndDecode(…) 执行请求并解码

Object executeAndDecode(RequestTemplate template, Request.Options options) throws Throwable {// 通过模版获取请求体,执行所有请求拦截器Request request = this.targetRequest(template);if (this.logLevel != Level.NONE) {this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);}long start = System.nanoTime();Response response;try {// 使用客户端执行请求response = this.client.execute(request, options);// 使用响应建造器构造一个响应体,包含请求和请求模板response = response.toBuilder().request(request).requestTemplate(template).build();} catch (IOException var9) {if (this.logLevel != Level.NONE) {this.logger.logIOException(this.metadata.configKey(), this.logLevel, var9, this.elapsedTime(start));}throw FeignException.errorExecuting(request, var9);}long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);// 处理响应结果&记录日志&响应解码return this.responseHandler.handleResponse(this.metadata.configKey(), response, this.metadata.returnType(), elapsedTime);}

通过分析,发现是先创建了RequestTemplate 实例,然后调用了client实例进行远程调用。而client的实现有多个,我这边看到内部实现了一个默认的:

public static class Default implements Client {public Response execute(Request request, Request.Options options) throws IOException {HttpURLConnection connection = this.convertAndSend(request, options);return this.convertResponse(connection, request);}
}

也就是说,到了这一步,就涉及到远程连接了。

这里用的是比较原始的HttpURLConnection。每次都创建新的连接,去请求,然后断开连接。这样很多时间也就浪费在建立连接等操作上了。而且调用量一旦变大,很容易出错。

问题来了,有没有什么办法能优化下呢?

四、如何更换client 的实现

上文提到 HttpURLConnection 是默认的连接方式。那麽我们有什么优化方案吗?
可替代方案一般有两种,一种是带有连接池的Apache HttpClient ,另一种是协议上占有优势的 OkHttp

至于它们的更详细的优缺点,以及不同之处,请查看本文的附2。

另外,我的下一篇文打算单独将这块写一下 ===> SpringCloud实用-OpenFeign整合okHttp
戳附录中的【本系列文章链接】查看文章。

附录

附1:本系列文章链接

SpringCloud系列文章目录(总纲篇)

附2:比较HttpURLConnection、Apache HttpClient、OkHttp

参考:七大主流的HttpClient程序比较

Client优点缺点
HttpURLConnectionjdk自带、原始、简单缺乏连接池管理、域名机械控制等特性支持,性能&效率较低,一般不建议使用
Apache HttpClient (已经停止开发)
Apache HttpComponents HttpClient
1. 支持连接池、多线程
2. 易用,灵活
安卓社区不再使用它,替换为了okHttp
需要自己做一层封装
java.net.http.HttpClientjava11正式启用,替代原先的HttpURLConnection如果使用的版本是java11以下的,用不了它
okHttp性能方面与HttpClient基本一样
链接复用
Response 缓存和 Cookie
默认 GZIP
请求失败自动重连
DNS 扩展
Http2/SPDY/WebSocket 协议支持
默认情况下,OKHttp会自动处理常见的网络问题:像二次连接、SSL的握手问题。
从Android4.4开始HttpURLConnection的底层实现采用的是okHttp.

一般情况下,如果使用了SpringCloud,基本都会选择 OpenFeign+okHttp的组合。

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

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

相关文章

【Python】生死簿管理系统,估值5毛

生死簿管理系统 代码 """ 生死簿管理系统 """ import os import timefile_name data.txtdef main():while True:main_menu()choice (int)(input("请选择: "))if choice in [0, 1, 2, 3, 4, 5, 6, 7]:if choice 0:answer input(&…

「树形」样式,数据关联超便捷丨三叠云

树形样式 路径 表单设计 >> 字段属性 功能简介 「表单关联」的数据列表样式支持「树形」样式功能&#xff0c;关联数据选择时通过「树形」的列表方式进行数据选择&#xff0c;提高生产效率。 使用场景&#xff1a; 可以通过树形列表样式展示部门、子部门、成员的树形…

30㎡新中式大横厅|方寸之间,诉说东方写意生活。福州中宅装饰,福州装修

今天要分享的是一个新中式风格的客厅装修&#xff0c;它的开间是4.5米&#xff0c;进深是6.5米。设计中有许多亮点&#xff0c;让我们一起来看看。 1️⃣ 首先&#xff0c;这个客厅采用了双眼皮无主灯吊顶的设计&#xff0c;让整个空间看起来更加高挑宽敞。吊顶的边缘线条简洁明…

Re53:读论文 How Can We Know What Language Models Know?

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;How Can We Know What Language Models Know? ArXiv网址&#xff1a;https://arxiv.org/abs/1911.12543 官方GitHub项目&#xff08;prompt之类的都有&#xff09;&#xff1a;https:…

详解Rust编程中的生命周期

1.摘要 生命周期在Rust编程中是一个重要概念, 它能确保引用像预期的那样一直有效。在Rust语言中, 每一个引用都有其生命周期, 通俗讲就是每个引用在程序执行的过程中都有其自身的作用域, 一旦离开其作用域, 其生命周期也宣告结束, 值不再有效。幸运的是, 在绝大多数时间里, 生…

15 reids哨兵机制

redis主机默认是10s发送一次心跳给从节点。 从节点默认1s去发送心跳给主节点。 1、原理 当主节点出现故障时&#xff0c;由Redis Sentinel自动完成故障发现和转移&#xff0c;并通知应用方&#xff0c;实现高可用性。 从节点的主要两个作用&#xff1a; 主节点的数据备份。…

【2023年APMCM亚太杯C题】完整代码+结果分析+论文框架

2023年APMCM亚太杯C题 完整代码结果分析论文框架第一问问题分析技术文档1 基于AHP的新能源汽车发展影响因素分析1.1 AHP模型的构建1.2 AHP模型的求解 2 基于自适应ARIMA-非线性回归模型的影响因素预测2.1 ARIMA模型的建立2.2 非线性回归模型的建立2.3 自适应混合ARIMA-非线性回…

【数据结构/C++】线性表_顺序表的基本操作

#include <iostream> using namespace std; #define MaxSize 10 // 1. 顺序表 // 静态分配 typedef struct {int data[MaxSize];int length; // 当前长度 } SqList; // 静态分配初始化顺序表 void InitList(SqList &L) {for (int i 0; i < MaxSize; i){L.data[i]…

政务大数据与资源平台建设解决方案:PPT全文75页,附下载

关键词&#xff1a;智慧政务解决方案&#xff0c;大数据解决方案&#xff0c;数据中心解决方案&#xff0c;数据治理解决方案 一、政务大数据与资源平台建设背景 1、政务大数据已成为智慧城市建设的必要基础 为响应国家不断加快5G基建、大数据、人工智能等新型基础设施建设布…

Redis的性能,哨兵模式,集群,

Redis的性能管理; redis的数据保存在内存中 redis-cli info memory redis内存使用info memory命令参数解析 used_memory:236026888 由 Redis 分配器分配的内存总量&#xff0c;包含了redis进程内部的开销和数据占用的内存&#xff0c;以字节&#xff08;byte&#xff09…

虚拟化原理

目录 什么是虚拟化广义虚拟化狭义虚拟化 虚拟化指令集敏感指令集虚拟化指令集的工作模式监视器对敏感指令的处理过程&#xff1a; 虚拟化类型全虚拟化类虚拟化硬件辅助虚拟化 虚拟化架构裸金属架构宿主机模式架构 什么是虚拟化 虚拟化就是通过模仿下层原有的功能模块创造接口来…

【开源】基于JAVA的衣物搭配系统

项目编号&#xff1a; S 016 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S016&#xff0c;文末获取源码。} 项目编号&#xff1a;S016&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 衣物档案模块2.2 衣物搭配模块2.3 衣…

常用数据存储格式介绍:Excel、CSV、JSON、XML

在现代数字时代&#xff0c;数据经过提炼后可以推动创新、简化运营并支持决策流程。然而&#xff0c;在提取数据之后&#xff0c;并将其加载到数据库或数据仓库之前&#xff0c;需要将数据转化为可用的数据存储格式。本文将介绍开发者常用的4种数据存储格式&#xff0c;包括 Ex…

布局下一个时代,UTONMOS夯实元宇宙发展基础

从 PC 互联网到移动互联网&#xff0c;再到元宇宙&#xff0c;互联网的发展在一直不断演变和升级着。元宇宙的时代红利将带来从底层基础设施向外延展到用户体验的全面升级。 人们以各自不同视角理解元宇宙。但我们认为&#xff0c;目前学术界和产业界对元宇宙虽然没有统一规范的…

css引入的三种方式

css引入的三种方式 一、内联样式二、外部样式表三、 内部样式表总结trouble 一、内联样式 内联样式也被称为行内样式。它是将 CSS 样式直接应用于 HTML 元素的 style 属性中的一种方式 <p style"color: blue; font-size: 16px;">这是一个带有内联样式的段落。&…

Modbus RTU转Profinet网关连接PLC与变频器通讯在机床上应用案例

背景&#xff1a;以前在机床加工车间里&#xff0c;工人们忙碌地操作着各种机床设备。为了使整个生产过程更加高效、流畅&#xff0c;进行智能化改造。 方案&#xff1a;在机床上&#xff0c;PLC通过Modbus RTU转Profinet网关连接变频器进行通讯&#xff1a;PLC作为整个生产线…

【封装UI组件库系列】封装Icon图标组件

封装UI组件库系列第三篇封装Icon图标组件 &#x1f31f;前言 &#x1f31f;封装Icon 1.创建Icon组件 2.引用svg图标库 第一步 第二步 第三步 3.二次封装 4.封装自定义属性 &#x1f31f;总结 &#x1f31f;前言 在前端开发中&#xff0c;大家可能已经用过各种各样的UI组…

VUE项目部署过程中遇到的错误:POST http://124.60.11.183:9090/test/login 405 (Not Allowed)

我当初报了这个405错误&#xff0c;再网上查了半天&#xff0c;他们都说什么是nginx部署不支持post访问静态资源。 但后面我发现我是因为另一个原因才导致的无法访问。 我再vue中有使用devServer:{ proxy:{} }进行路由转发。 但是&#xff01;&#xff01; 在这个配置只…

接口测试学习路线

接口测试分为两种&#xff1a; 测试外部接口&#xff1a;系统和外部系统之间的接口 如&#xff1a;电商网站&#xff1a;支付宝支付 测试内部接口&#xff1a;系统内部的模块之间的联调&#xff0c;或者子系统之间的数据交互 测试重点&#xff1a;测试接口参数传递的正确性&…

node与 pnpm、node-sass 等工具的版本兼容关系

1. node & pnpm 2. node & node-sass 3. node-sass & sass-loader sass-loader依赖于node-sass&#xff0c;以下是部分版本号对应