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.pswp.cn/news/166653.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/166653.shtml
英文地址,請注明出處:http://en.pswp.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基建、大數據、人工智能等新型基礎設施建設布…

在MySQL中,修改字段A相同的記錄的字段B ,要使得字段C小的記錄的字段B值等于字段C大的記錄的字段B值

例如&#xff1a;更新具有相同電話號碼的用戶記錄&#xff0c;使得updatetime小的記錄的name值等于updatetime大的記錄的name值。 首先&#xff0c;我們需要創建一個用戶表&#xff0c;這個用戶表包含以下字段&#xff1a;phone&#xff0c;updatetime, name。以下是創建這個表…

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

Redis的性能管理; redis的數據保存在內存中 redis-cli info memory redis內存使用info memory命令參數解析 used_memory:236026888 由 Redis 分配器分配的內存總量&#xff0c;包含了redis進程內部的開銷和數據占用的內存&#xff0c;以字節&#xff08;byte&#xff09…

css里面的@import

import 說明 用于從其他樣式表導入樣式規則。可以是絕對或相對路徑&#xff0c;也可以是一個在線的url地址。import 規則必須在 CSS 文檔的頭部&#xff0c;但可以在 charset 規則后面。import 規則不是一個嵌套語句&#xff0c;import不能在條件組的規則中使用。import 規則…

虛擬化原理

目錄 什么是虛擬化廣義虛擬化狹義虛擬化 虛擬化指令集敏感指令集虛擬化指令集的工作模式監視器對敏感指令的處理過程&#xff1a; 虛擬化類型全虛擬化類虛擬化硬件輔助虛擬化 虛擬化架構裸金屬架構宿主機模式架構 什么是虛擬化 虛擬化就是通過模仿下層原有的功能模塊創造接口來…

【開源】基于JAVA的衣物搭配系統

項目編號&#xff1a; S 016 &#xff0c;文末獲取源碼。 \color{red}{項目編號&#xff1a;S016&#xff0c;文末獲取源碼。} 項目編號&#xff1a;S016&#xff0c;文末獲取源碼。 目錄 一、摘要1.1 項目介紹1.2 項目錄屏 二、研究內容2.1 衣物檔案模塊2.2 衣物搭配模塊2.3 衣…

linux進程調度(二)-進程創建

文章目錄 2.進程創建和終止2.1 進程創建的4種方法2.2 進程創建過程分析2.2.1 copy_process函數分析2.2.1.1 dup_task_struct函數分析2.2.1.2 sched_fork函數分析2.2.1.3 copy_mm函數分析2.2.1.4 copy_thread函數分析 2.2.2 wake_up_new_task函數分析 2.進程創建和終止 在 Linu…

常用數據存儲格式介紹:Excel、CSV、JSON、XML

在現代數字時代&#xff0c;數據經過提煉后可以推動創新、簡化運營并支持決策流程。然而&#xff0c;在提取數據之后&#xff0c;并將其加載到數據庫或數據倉庫之前&#xff0c;需要將數據轉化為可用的數據存儲格式。本文將介紹開發者常用的4種數據存儲格式&#xff0c;包括 Ex…

布局下一個時代,UTONMOS夯實元宇宙發展基礎

從 PC 互聯網到移動互聯網&#xff0c;再到元宇宙&#xff0c;互聯網的發展在一直不斷演變和升級著。元宇宙的時代紅利將帶來從底層基礎設施向外延展到用戶體驗的全面升級。 人們以各自不同視角理解元宇宙。但我們認為&#xff0c;目前學術界和產業界對元宇宙雖然沒有統一規范的…

JavaScript 閉包技巧

什么是閉包&#xff1f; MDN&#xff1a;“閉包是捆綁在一起&#xff08;封閉&#xff09;的函數及其周圍狀態&#xff08;詞法環境&#xff09;的引用的組合。換句話說&#xff0c;閉包使您可以從內部函數訪問外部函數的作用域。在 JavaScript 中&#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作為整個生產線…