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标注的接口方法。这篇文章,我们就来看看它的原理。
本文关键词:RequestTemplate
、SynchronousMethodHandler
使用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.FeignInvocationHandler
的invoke(...)
方法。
二、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 | 优点 | 缺点 |
---|---|---|
HttpURLConnection | jdk自带、原始、简单 | 缺乏连接池管理、域名机械控制等特性支持,性能&效率较低,一般不建议使用 |
Apache HttpClient (已经停止开发) Apache HttpComponents HttpClient | 1. 支持连接池、多线程 2. 易用,灵活 | 安卓社区不再使用它,替换为了okHttp 需要自己做一层封装 |
java.net.http.HttpClient | java11正式启用,替代原先的HttpURLConnection | 如果使用的版本是java11以下的,用不了它 |
okHttp | 性能方面与HttpClient基本一样 链接复用 Response 缓存和 Cookie 默认 GZIP 请求失败自动重连 DNS 扩展 Http2/SPDY/WebSocket 协议支持 默认情况下,OKHttp会自动处理常见的网络问题:像二次连接、SSL的握手问题。 从Android4.4开始HttpURLConnection的底层实现采用的是okHttp. | |
一般情况下,如果使用了SpringCloud,基本都会选择 OpenFeign+okHttp的组合。
相关文章:

SpringCloud原理-OpenFeign篇(四、请求原理)
文章目录 前言正文一、书接上回,从代理对象入手二、ReflectiveFeign.FeignInvocationHandler#invoke()三、SynchronousMethodHandler#invoke(...) 的实现原理3.1 invoke(...)源码3.2 executeAndDecode(...) 执行请求并解码 四、如何更换client 的实现 附录附1&#…...

什么是工业物联网(IOT)?这样的IOT平台你需要吗?——青创智通
物联网(IOT)是指在互联网上为传输和共享数据而嵌入传感器和软件的互联设备的广泛性网络。这允许将从物理对象收集的信息(数据)存储在专用服务器或云中。通过分析这些积累的信息,通过提供最优的设备控制和方法,可以实现一个更安全、更方便的社会。在智能家…...
MTK Pump Express 快速充电原理分析
1 MTK PE 1.1 原理 在讲正文之前,我们先看一个例子。 对于一块电池,我们假设它的容量是6000mAh,并且标称电压是3.7V,换算成Wh(瓦时)为单位的值是22.3Wh(6000mAh*3.7V);普通的充电器输出电压电流是5V2A(10W),…...
leetcode刷题记录——1991. 找到数组的中间位置
找到数组的中间位置 给你一个下标从 0 开始的整数数组 nums ,请你找到 最左边 的中间位置 middleIndex (也就是所有可能中间位置下标最小的一个)。 中间位置 middleIndex 是满足 nums[0] nums[1] … nums[middleIndex-1] nums[middleInd…...

跨域攻击分析和防御(上)
点击星标,即时接收最新推文 跨域攻击 在大型公司或大型跨国企业中都拥有自己的内网,跨国公司都有各个子公司一般以建立域林进行共享资源。根据不同职能区分的部门,从逻辑上以主域和子域进行划分以方便统一管理。在物理层使用防火墙将各个子公…...

GEE:梯度提升树(Gradient Boosting Tree)分类教程(样本制作、特征添加、训练、精度、参数优化、贡献度、统计面积)
作者:CSDN @ _养乐多_ 本文将介绍在Google Earth Engine (GEE)平台上进行梯度提升树(Gradient Boosting Tree)分类的方法和代码,其中包括制作样本点教程(本地、在线和本地在线混合制作样本点,合并样本点等),加入特征变量(各种指数、纹理特征、时间序列特征、物候特征…...

ubuntu22.04 arrch64版在线安装redis
脚本 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32 echo "deb http://archive.ubuntu.com/ubuntu/ trusty main universe restricted multiverse" >…...

篮桥云课-摆玩具
思维好题 一开始掉进了二分的陷阱,发现看看逐个位置的差,我们要分成k段就是要取消k-1个最大的逐差 然后将剩余的加起来就可以了 因为本体保证是从小到大给出的 这一点保证了答案的正确性,自己没想出来 还是太菜了 #include<bits/stdc.h&…...
【python】python进阶知识点
eval函数用法 函数参数:字符串 # 计算表达式 print(eval("12*3")) # 把字符串当成python程序运行 print(eval("random.random()")) # 字符串转成列表 print(type(eval("[1,2,3,4]"))) # 字符串转成字典 print(type(eval("{name…...
LeetCode算法题解(动态规划)|LeetCode322. 零钱兑换、LeetCode279. 完全平方数
一、LeetCode322. 零钱兑换 题目链接:322. 零钱兑换 题目描述: 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一…...

Python Web开发基础知识篇
一,基础知识篇 本片文章会简单地说一些python开发web中所必须的一些基础知识。主要包括HTML和css基础、JavaScript基础、网络编程基础、MySQL数据库基础、Web框架基础等知识。 1,Web简介 Web,全称为World Wide Web,也就是WWW,万…...

企业计算机服务器中了360勒索病毒怎么办,360勒索病毒解密文件恢复
计算机技术的不断发展,为企业的生产运营提供了极大便利,不仅提升了办公效率,还促进了企业的发展。企业计算机在日常工作中一定加以防护,减少网络威胁事件的产生,确保企业的生产生产运营。最近,网络上的360后…...
LeetCode无重复字符的最长字符串的Java实现
题目 给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子字符串是 "abc",所以其长度为 3。示例 2: 输入: s "bbbbb" 输…...

opencv-图像平滑
高斯平滑 高斯平滑即采用高斯卷积核对图像矩阵进行卷积操作。高斯卷积核是一个近似服从高斯分布的矩阵,随着距离中心点的距离增加,其值变小。这样进行平滑处理时,图像矩阵中锚点处像素值权重大,边缘处像素值权重小。 import cv2 …...

【开源】基于Vue.js的天然气工程运维系统的设计和实现
项目编号: S 022 ,文末获取源码。 \color{red}{项目编号:S022,文末获取源码。} 项目编号:S022,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统角色分类2.2 核心功能2.2.1 流程…...

数据丢失抢救神器之TOP10 Android 数据恢复榜单
在快节奏的数字时代,我们的生活越来越与智能手机交织在一起,使它们成为重要数据和珍贵记忆的存储库。由于意外删除、软件故障或硬件故障而丢失数据可能是一种痛苦的经历。值得庆幸的是,技术领域提供了 Android 数据恢复软件形式的解决方案。这…...

梨花声音教育,动作电影中配音也能带来听见“冲击力”
在为动作电影提供配音服务时,配音员家需要通过声音的力量来增强画面上的动作张力、传递角色的活力,以及呈现出电影中的紧迫感。动作片充斥着快节奏的场景交替、紧张的格斗和惊险的逃逸等元素,配音需要精确、生动且充满动力。为动作电影配音应…...
Elaticsearch学习
Elaticsearch 索引 1、索引创建 PUT /index_v1 {"settings": {"number_of_shards": 3,"number_of_replicas": 1},"mappings": {"properties": {"aaa": {"type": "keyword","store&qu…...

【腾讯云云上实验室】向量数据库+LangChain+LLM搭建智慧辅导系统实践
目录 一、搭建智慧辅导系统——向量数据库实践指南1.1、创建向量数据库并新建集合1.2、使用 TKE 快速部署 ChatGLM1.3、部署 LangChain PyPDFVectorDB等组件1.4、配置知识库语料1.5、基于 VectorDB LLM 的智能辅导助手 二、LLM时代的次世代引擎——向量数据库2.1、向量数据库L…...

从0开始学习JavaScript--深入了解JavaScript框架
JavaScript框架在现代Web开发中扮演着关键角色,为开发者提供了丰富的工具和抽象层,使得构建复杂的、高性能的Web应用变得更加容易。本文将深入探讨JavaScript框架的核心概念、常见框架的特点以及它们在实际应用中的使用。 JavaScript框架的作用 JavaSc…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...