日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

我試圖通過這篇文章告訴你,什么是神奇的泛化調(diào)用。

來源: 責編: 時間:2023-11-30 09:26:53 250觀看
導讀你好呀,我是歪歪。關于 RPC 調(diào)用,大家肯定都是比較熟悉的了,就是在微服務架構(gòu)下解決系統(tǒng)間通信問題的一個玩意。其中的典型代表之一就是 Dubbo 了:圖片在微服務架構(gòu)下,我們針對某個 RPC 接口,我們一般有兩個角色。服務消費

你好呀,我是歪歪。Uj028資訊網(wǎng)——每日最新資訊28at.com

關于 RPC 調(diào)用,大家肯定都是比較熟悉的了,就是在微服務架構(gòu)下解決系統(tǒng)間通信問題的一個玩意。Uj028資訊網(wǎng)——每日最新資訊28at.com

其中的典型代表之一就是 Dubbo 了:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

在微服務架構(gòu)下,我們針對某個 RPC 接口,我們一般有兩個角色。Uj028資訊網(wǎng)——每日最新資訊28at.com

  • 服務消費者 (Dubbo Consumer),發(fā)起業(yè)務調(diào)用或 RPC 通信的 Dubbo 進程
  • 服務提供者 (Dubbo Provider),接收業(yè)務調(diào)用或 RPC 通信的 Dubbo 進程

假設我是服務消費者,想要調(diào)用某個服務,只要我們鏈接到的是同一個服務注冊中心,那么找對應服務要到 API 包對應的 Maven 坐標,引入到項目中,就類似于這樣的東西:Uj028資訊網(wǎng)——每日最新資訊28at.com

<dependency>    <groupId>org.apache.dubbo</groupId>    <artifactId>dubbo-spring-boot-demo-interface</artifactId>    <version>${project.parent.version}</version></dependency>

那么對于這個 API 包中的接口,雖然我們沒有具體的實現(xiàn)類,但是我們還是能像調(diào)用本地方法一樣調(diào)用該服務提供的接口。Uj028資訊網(wǎng)——每日最新資訊28at.com

這些都是常規(guī)的東西了,你肯定是門清。Uj028資訊網(wǎng)——每日最新資訊28at.com

那我現(xiàn)在問你一個問題啊:Uj028資訊網(wǎng)——每日最新資訊28at.com

我是服務消費者,我要調(diào)用一個服務提供者的 RPC 接口,但是我又不想引入它的 API 包,或者我根本就拉取不到它的 API 包,那么我應該怎么辦?Uj028資訊網(wǎng)——每日最新資訊28at.com

如果你要非給我說:這不可能,既然是要消費別人的接口,那么肯定要拿到 API 包才對,你不拿就是你偷懶。Uj028資訊網(wǎng)——每日最新資訊28at.com

那我再給你舉個歪師傅在實際開發(fā)過程中遇到的具體的例子:網(wǎng)關服務。Uj028資訊網(wǎng)——每日最新資訊28at.com

網(wǎng)關是個什么玩意?Uj028資訊網(wǎng)——每日最新資訊28at.com

是你對外請求的統(tǒng)一入口,做接受請求、分發(fā)請求用的,作為鏈接各個微服務的角色,你勢必要使用到下游的若干個 RPC 服務。Uj028資訊網(wǎng)——每日最新資訊28at.com

你怎么辦?Uj028資訊網(wǎng)——每日最新資訊28at.com

引入所有的服務提供方的 API 包,然后發(fā)起調(diào)用嗎?Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

可以是可以,但是不夠優(yōu)雅。Uj028資訊網(wǎng)——每日最新資訊28at.com

你想,如果有一個服務提供方發(fā)布了新的 API 包,你也需要更新版本,重新發(fā)版?Uj028資訊網(wǎng)——每日最新資訊28at.com

或者新來一個服務提供者 E,你需要引入其 API 包,然后重新發(fā)版?Uj028資訊網(wǎng)——每日最新資訊28at.com

網(wǎng)關應該是一個穩(wěn)定的基礎服務,它提供的是聚攏 API 接口、轉(zhuǎn)發(fā)調(diào)用的基礎功能,不應該頻繁發(fā)版,不應該主動去關注下游的服務接口變化。平臺本身不應該依賴于服務提供方的接口 API。Uj028資訊網(wǎng)——每日最新資訊28at.com

不主動,才能更加優(yōu)雅,也能讓自己更加輕松。Uj028資訊網(wǎng)——每日最新資訊28at.com

那么怎么才能做到不主動關注呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

這個事情,總有一方要主動的,所以網(wǎng)關層不主動,那么服務提供者就需要主動起來。Uj028資訊網(wǎng)——每日最新資訊28at.com

我們可以搞成這樣:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

網(wǎng)關層提供一個 API 接口發(fā)布平臺,當服務提供者的接口有新增或者發(fā)生變化的時候,由對應系統(tǒng)的接口管理人員把接口信息,比如接口路徑、方法、入?yún)ⅰ⒊鰠ⅰ⒎椒üδ苷f明、方法負責團隊、接口對接人等等這些消息維護到 API 接口發(fā)布平臺上。Uj028資訊網(wǎng)——每日最新資訊28at.com

這樣網(wǎng)關層就可以從 API 接口發(fā)布平臺獲取到所有服務的所有接口,并不需要引入任何服務提供者的 API 包。Uj028資訊網(wǎng)——每日最新資訊28at.com

這樣就解決了“主動”的問題,如果接口有變化,請在 API 接口發(fā)布平臺進行登記,從而解決了網(wǎng)關頻繁發(fā)布的問題。Uj028資訊網(wǎng)——每日最新資訊28at.com

在官網(wǎng)上,除了網(wǎng)關的場景外,還提到一個測試平臺的場景,道理是一樣的,我就不贅述了:Uj028資訊網(wǎng)——每日最新資訊28at.com

https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

解決了“主動”的問題,那么下一個問題就隨之而來了:知道所有服務的所有接口然后呢,怎么發(fā)起調(diào)用呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

這個時候泛化調(diào)用,啪的一下就站出來了:鋪墊了這么多,終于該老子上場了。Uj028資訊網(wǎng)——每日最新資訊28at.com

泛化調(diào)用

啥是泛化調(diào)用呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

在 Dubbo 官網(wǎng)上是這樣介紹的:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

首先需要強調(diào)的是“泛化調(diào)用”不是 Dubbo 特有的,它是一個功能,很多的框架都支持泛化調(diào)用,只是我這里用的 Dubbo 做演示而已。Uj028資訊網(wǎng)——每日最新資訊28at.com

老規(guī)矩,先花五分鐘時間搭個 Demo 出來再說。Uj028資訊網(wǎng)——每日最新資訊28at.com

這個 Demo 我也是跟著網(wǎng)上的 quick start 搞的:Uj028資訊網(wǎng)——每日最新資訊28at.com

https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/spring-boot/Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

可以說寫的非常詳細了,你就跟著官網(wǎng)的步驟一步步的搞就行了。Uj028資訊網(wǎng)——每日最新資訊28at.com

我這個 Demo 稍微不一樣的是我在消費者模塊里面搞了一個 Http 接口:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

在接口里面發(fā)起了 RPC 調(diào)用,模擬從前端頁面發(fā)起請求的場景,更加符合我們的開發(fā)習慣。Uj028資訊網(wǎng)——每日最新資訊28at.com

為了起到強調(diào)作用,我再次把這個部分給你框起來:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

DemoService 是 RPC 接口,它的實現(xiàn)類是這樣的:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

在我的消費者模塊里面為什么能注入這個 DemoService 并調(diào)用它的 sayHello 方法呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

因為我引入了對應的依賴包。Uj028資訊網(wǎng)——每日最新資訊28at.com

那么,如果我把這個依賴包去掉,也就是模擬我們前面說的“不主動”的動作,這個 DemoService 肯定會報錯,找不到這個類:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

那么我們應該怎么去修改一下這個 Demo,讓它泛化起來呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

非常簡單:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

注入 DemoService 修改為注入 GenericService。Uj028資訊網(wǎng)——每日最新資訊28at.com

有的小伙伴可能會問 GenericService 是怎么冒出來的?Uj028資訊網(wǎng)——每日最新資訊28at.com

你先別管它是怎么冒出來的,我現(xiàn)在是在給你鋪墊 Demo,后面要撕給你看。你現(xiàn)在只需要知道它是 Dubbo 框架里面的包,并不會讓你引用額外的包就行了:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

現(xiàn)在 Demo 就算是搭好了,本地啟動一個 zk,然后把服務提供者啟動起來,再把消費者啟動起來,最后輕輕的發(fā)起一個調(diào)用:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

朋友,它不就跑起來了嗎?Uj028資訊網(wǎng)——每日最新資訊28at.com

我沒有引用接口的 api 包,我不也正常發(fā)起了調(diào)用,然后拿到了返回值嗎?Uj028資訊網(wǎng)——每日最新資訊28at.com

啥原理

你就想,遠程調(diào)用,你把一些花里胡哨的東西都拿掉之后,它的本質(zhì)是什么?Uj028資訊網(wǎng)——每日最新資訊28at.com

本質(zhì)就是幫助解決微服務組件之間的通信問題,不管是基于  HTTP、HTTP/2、TCP 還是什么其他的通信協(xié)議,解決的是網(wǎng)絡連接管理、數(shù)據(jù)傳輸?shù)然A問題。Uj028資訊網(wǎng)——每日最新資訊28at.com

雖然我沒有引用 API 的對應的包,但是我前面我不是說了嗎,我們有一個 API 接口發(fā)布平臺,這個平臺里面有接口維護人員提供的接口路徑、方法、入?yún)ⅰ⒊鰠⑦@些關鍵信息。Uj028資訊網(wǎng)——每日最新資訊28at.com

所以我在調(diào)用的時候可以拿到相關的信息,以一種通用的方式,比如字符串的方式告訴 RPC 框架,我要調(diào)用的是 DemoService 接口的 sayHello 方法,入?yún)⑹?String 類型的 world 字符串:Uj028資訊網(wǎng)——每日最新資訊28at.com

如果是你來開發(fā)一個 RPC 框架,調(diào)用方都把這些關鍵信息給你了,無非就是你幫忙多做幾步類似于反射、序列化之類的處理。而處理的這個過程,就是泛化調(diào)用的過程。Uj028資訊網(wǎng)——每日最新資訊28at.com

泛化調(diào)用不是 Dubbo 特有的,但是具體到 Dubbo 這個框架里面,具體是這樣的。Uj028資訊網(wǎng)——每日最新資訊28at.com

首先,Dubbo 里面有一層 Filter,這些 Filter 構(gòu)成了一個 Filter 鏈條:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

Filter 用來對每次服務調(diào)用做一些預處理、后處理動作,使用 Filter 可以完成訪問日志、加解密、流量統(tǒng)計、參數(shù)驗證等任務。Uj028資訊網(wǎng)——每日最新資訊28at.com

一次請求過程中可以植入多個 Filter,F(xiàn)ilter 之間相互獨立沒有依賴。Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

從消費端視角,它在請求發(fā)起前基于請求參數(shù)等做一些預處理工作,在接收到響應后,對響應結(jié)果做一些后置處理。Uj028資訊網(wǎng)——每日最新資訊28at.com

從提供者視角,在接收到訪問請求后,在返回響應結(jié)果前做一些預處理。Uj028資訊網(wǎng)——每日最新資訊28at.com

所以我們的泛化調(diào)用,也是通過下面這兩個 Filter 來搞事情的:Uj028資訊網(wǎng)——每日最新資訊28at.com

  • org.apache.dubbo.rpc.filter.GenericFilter
  • org.apache.dubbo.rpc.filter.GenericImplFilter

那么問題就來了?Uj028資訊網(wǎng)——每日最新資訊28at.com

為什么要兩個 Filter 呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

因為要完成一次泛化調(diào)用,消費端和服務提供者都需要感知到并做相關的處理,所以一個是消費端的 Fliter,一個是服務提供者的 Fliter:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

知道了對應的 Filter,關于泛化調(diào)用的所有秘密都藏在 Filter 對應的源碼里面。Uj028資訊網(wǎng)——每日最新資訊28at.com

歪師傅帶著你簡單的看一眼。Uj028資訊網(wǎng)——每日最新資訊28at.com

GenericImplFilter.invoke

首先,我們在方法的消費者對應的 Fliter 的入口處打上斷點:Uj028資訊網(wǎng)——每日最新資訊28at.com

org.apache.dubbo.rpc.filter.GenericImplFilter#invokeUj028資訊網(wǎng)——每日最新資訊28at.com

可以看到分為了三個模塊。Uj028資訊網(wǎng)——每日最新資訊28at.com

  • isCallingGenericImpl:calling a generic impl service,判斷是否調(diào)用的是一個實現(xiàn)了泛化接口的接口。
  • isMakingGenericCall:making a generic call to a normal service,把泛化調(diào)用轉(zhuǎn)換為一個常規(guī)調(diào)用。
  • invoker.invoke(invocation):常規(guī)調(diào)用。

我們研究的情況屬于 isMakingGenericCall 這個分支。Uj028資訊網(wǎng)——每日最新資訊28at.com

既然是要把泛化調(diào)用轉(zhuǎn)換為一個常規(guī)調(diào)用,那么 Dubbo 是怎么判斷這是一個泛化調(diào)用的呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

org.apache.dubbo.rpc.filter.GenericImplFilter#isMakingGenericCallUj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

  • 判斷本次調(diào)用的方法名稱是否是 或者invokeAsync
  • 判斷本次調(diào)用的入?yún)€數(shù)是否是 3 個
  • 判斷容器上下文中的 generic 參數(shù)是否對應著泛化調(diào)用的序列化方法。

我們一個個的看。Uj028資訊網(wǎng)——每日最新資訊28at.com

或者invokeAsync 方法是 GenericService 這個接口里面的方法。而這兩個方法的入?yún)€數(shù)都是三個。Uj028資訊網(wǎng)——每日最新資訊28at.com

然后有個 generic 參數(shù),在我的 Demo 里面這個參數(shù)是 true:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

當我啪的一下跟進到 isGeneric 方法中,才發(fā)現(xiàn)這里面別有洞天:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

原來 generic 這個參數(shù)不只是可以為 “true”,它不同的值,代表著不同的序列化方式。Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

通過這部分源碼可以看出來,泛化調(diào)用對于客戶端,即在 GenericImplFilter 里面,并沒有做什么特別的操作,注意還是參數(shù)校驗。Uj028資訊網(wǎng)——每日最新資訊28at.com

如果入?yún)⒑蛯男蛄谢椒ú荒芷ヅ淦饋恚词沟膾伋霎惓?,這樣符合 Dubbo 框架的 fast-fail 思想。Uj028資訊網(wǎng)——每日最新資訊28at.com

但是其實看到這里的時候,我有一個小疑問,如果我寫一個這樣的類:Uj028資訊網(wǎng)——每日最新資訊28at.com

public interface WhyService {    Object $invoke(String a,String b,String c);}

和 GenericService 類一樣,有 $invoke 方法,而且也是三個參數(shù)。Uj028資訊網(wǎng)——每日最新資訊28at.com

然后在上下文中塞個 generic=true 進去,那么是不是也能騙過這段代碼呢,也能進入到 isMakingGenericCall 方法里面呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

從代碼上看確實是這樣的,那么 Dubbo 到底是怎么規(guī)避這些“惡意”冒充者的呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

我也不知道。Uj028資訊網(wǎng)——每日最新資訊28at.com

先存?zhèn)€疑吧,接著往下看。Uj028資訊網(wǎng)——每日最新資訊28at.com

GenericFilter.invoke

我們同樣在服務端打上斷點,當這個請求來到服務端的時候,我們再看看服務端的情況。Uj028資訊網(wǎng)——每日最新資訊28at.com

org.apache.dubbo.rpc.filter.GenericFilter#invokeUj028資訊網(wǎng)——每日最新資訊28at.com

可以看到這個方法邏輯都在 if 判斷為 true 的時候。Uj028資訊網(wǎng)——每日最新資訊28at.com

而這個判斷我們剛剛在客戶端已經(jīng)解析過了,只是多了一個判斷:Uj028資訊網(wǎng)——每日最新資訊28at.com

!GenericService.class.isAssignableFrom(invoker.getInterface())Uj028資訊網(wǎng)——每日最新資訊28at.com

看看發(fā)起調(diào)用的接口類是不是 GenericService 類的子類,如果是,則進入到 if 分支里面。Uj028資訊網(wǎng)——每日最新資訊28at.com

朋友,這就有點意思了。幾秒鐘之前我們還在存疑,然后啪的一下疑問就解開了。Uj028資訊網(wǎng)——每日最新資訊28at.com

直接就是恍然大悟了。Uj028資訊網(wǎng)——每日最新資訊28at.com

我這個類:Uj028資訊網(wǎng)——每日最新資訊28at.com

public interface WhyService {    Object $invoke(String a,String b,String c);}

過不了服務提供者的 GenericFilter 里面的這個判斷:Uj028資訊網(wǎng)——每日最新資訊28at.com

!GenericService.class.isAssignableFrom(invoker.getInterface())Uj028資訊網(wǎng)——每日最新資訊28at.com

在 invoke 方法里面,可以看到經(jīng)過了一個 findMethodByMethodSignature 方法,獲取了我們想要調(diào)用的 method 方法:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

這個方法,從名字上也可以看出,是根據(jù)方法簽名反射出具體的方法:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

在服務端,是有 DemoService 接口對應的類的,所以可以通過反射找到它。Uj028資訊網(wǎng)——每日最新資訊28at.com

然后再解析出入?yún)⒌木唧w值:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

這樣你就有了構(gòu)建一個 RpcInvocation 對象,即發(fā)起 RPC 調(diào)用的對象的所有關鍵消息。Uj028資訊網(wǎng)——每日最新資訊28at.com

直接就是發(fā)動一招“貍貓換太子”的大動作,重新構(gòu)建一個 RpcInvocation 對象,然后自己發(fā)起一個 invoke 調(diào)用。Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

這樣整體看起來似乎一次泛化調(diào)用也是很簡單的,當你去看服務提供端的源碼的時候,你會發(fā)現(xiàn)這里面的源碼特別多。Uj028資訊網(wǎng)——每日最新資訊28at.com

不過是因為 Dubbo 支持了多種不同的序列化方式而已,本質(zhì)是一樣的:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

onResponse 方法也是同理,就不贅述了:Uj028資訊網(wǎng)——每日最新資訊28at.com

org.apache.dubbo.rpc.filter.GenericFilter#onResponseUj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

到這里就算是扯下了泛化調(diào)用的神秘面紗,和我們預想的一樣,無非是拿到接口調(diào)用的關鍵信息之后,重新構(gòu)建一個請求而已,整體邏輯并不復雜。Uj028資訊網(wǎng)——每日最新資訊28at.com

復雜的邏輯是什么?Uj028資訊網(wǎng)——每日最新資訊28at.com

我演示的是最簡單的,入?yún)⑹且粋€ String 類型的情況。如果我是一個復雜對象呢,對象里面的成員變量特別多,對象里面套對象,對象里面有 List 或者 Map 的情況呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

復雜的地方在于怎么處理這些復雜對象,把復雜對象搞成服務提供者的 Java 對象入?yún)ⅰ?span style="display:none">Uj028資訊網(wǎng)——每日最新資訊28at.com

我這里只是一個導讀而已,如果你對這部分有興趣的話,自己搞個復雜對象去研究研究吧,老有意思了。Uj028資訊網(wǎng)——每日最新資訊28at.com

就當是家庭作業(yè)了。Uj028資訊網(wǎng)——每日最新資訊28at.com

意外收獲

歪師傅在扯面紗的時候,沒想到還有意外收獲。Uj028資訊網(wǎng)——每日最新資訊28at.com

給你看一段代碼,也是前面出現(xiàn)過的一個方法,我把完整的代碼都截圖放出來:Uj028資訊網(wǎng)——每日最新資訊28at.com

org.apache.dubbo.common.utils.ReflectUtils#findMethodByMethodSignatureUj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

你瞅瞅我框起來部分的 signature 字段,是不是沒有任何卵用?Uj028資訊網(wǎng)——每日最新資訊28at.com

自信一點,不要懷疑,確實沒有任何用處,signature 只是賦了個值而已,后續(xù)的代碼中并沒有使用。Uj028資訊網(wǎng)——每日最新資訊28at.com

所以,我小腦瓜子一轉(zhuǎn),立刻察覺到這又是一個水 pr 的好機會。Uj028資訊網(wǎng)——每日最新資訊28at.com

于是...Uj028資訊網(wǎng)——每日最新資訊28at.com

https://github.com/apache/dubbo/pull/13382Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

晚上 10 點半的時候,直接就是一個貢獻源碼的大動作,小手一揮,帶走四行代碼:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

當時我沒細想,但是后來躺在床上的時候我突然想起來:不應該啊,這個地方為什么會留著幾行看起來是沒有刪除不干凈的代碼呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

隱隱覺得這里面應該是有故事的。Uj028資訊網(wǎng)——每日最新資訊28at.com

于是看了這個類的提交記錄,主要找兩個地方:這個 signature 是什么時候有的,又是什么時候沒的。Uj028資訊網(wǎng)——每日最新資訊28at.com

在 2012 年 6 月 15 日,針對這個類做了一次性能優(yōu)化:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

優(yōu)化的具體內(nèi)容就是用 Map 把方法緩存起來,以免每次都需要去走反射的邏輯。Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

看完這個提交之后我覺得很合理啊,使用 Map 緩存一下確實屬于性能優(yōu)化。Uj028資訊網(wǎng)——每日最新資訊28at.com

那么為什么又把這個 Map 拿走了呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

于是我在 2021 年 9 月 6 日的提交中找到了拿走 Map 對應的提交記錄:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

這次提交的內(nèi)容非常的多,而從提交記錄的 log 中并沒有找到為什么要移除這個 Map 的原因:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

怎么辦?Uj028資訊網(wǎng)——每日最新資訊28at.com

很簡單,社區(qū)提問就行了。Uj028資訊網(wǎng)——每日最新資訊28at.com

于是我在我的 pr 下面拋出了自己的問題:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

我查看了該類的提交歷史,發(fā)現(xiàn) #8684 刪除了 ReflectUtils.java 中的所有 Map 緩存,遺留了對 signature  字段的處理。
但是我不明白為什么要刪除緩存,在我看來應該保留緩存。能說一下官方是怎么考慮的嗎?Uj028資訊網(wǎng)——每日最新資訊28at.com

很快我就得到了官方的回復:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

刪除緩存的原因是因為這些 Map 緩存是全局變量,這會導致從 Dubbo 的類(通常是 GC root)到對應類的引用,而這些類在 ClassLoader 被閑置后無法釋放。Uj028資訊網(wǎng)——每日最新資訊28at.com

啥意思呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

我大概的解釋一下。Uj028資訊網(wǎng)——每日最新資訊28at.com

首先,我們看一下這個 Map 的定義是怎么樣的:Uj028資訊網(wǎng)——每日最新資訊28at.com

private static final ConcurrentMap<String, Method> SIGNATURE_METHODS_CACHE = new ConcurrentHashMap<String, Method>();Uj028資訊網(wǎng)——每日最新資訊28at.com

它是個 static 對象,那么它是不是會被作為一個 GC root?Uj028資訊網(wǎng)——每日最新資訊28at.com

如果它作為一個 GC root,它里面緩存的這些方法,是不是都是“可達的”?Uj028資訊網(wǎng)——每日最新資訊28at.com

方法是可達的,那么這些方法對應的 Class 類是不是也是“可達的”?Uj028資訊網(wǎng)——每日最新資訊28at.com

但是在這些方法對應的 Class 類的 ClassLoader 完成自己的使命,被回收之后,那么這個 Class 類是不是理論上也可以被回收了?Uj028資訊網(wǎng)——每日最新資訊28at.com

但是實際情況是什么呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

實際情況是因為這個 static 對象還持有其引用,導致它不會被回收。Uj028資訊網(wǎng)——每日最新資訊28at.com

基于這個考慮,官方?jīng)Q定移除這個 Map。Uj028資訊網(wǎng)——每日最新資訊28at.com

其實我個人覺得,如果我上面的理解沒有錯的話,那么討論這個 Map 的效果,可以得兩個分情況:Uj028資訊網(wǎng)——每日最新資訊28at.com

如果一個泛化調(diào)用的調(diào)用頻率非常低,那么你把對應的方法緩存起來,導致 GC 一直回收不了,確實沒啥意思。Uj028資訊網(wǎng)——每日最新資訊28at.com

如果一個泛化調(diào)用的調(diào)用頻率比較高,那么你把對應的方法緩存起來,確實能起到“性能優(yōu)化”的效果。Uj028資訊網(wǎng)——每日最新資訊28at.com

那么 Dubbo 作為一個框架怎么知道你的這個方法調(diào)用的頻率高不高呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

它也不知道,所以干脆不要替用戶多做這一步,做多了,反而容易出錯。Uj028資訊網(wǎng)——每日最新資訊28at.com

其實它也是可以知道的,比如可以提供一個參數(shù)給用戶進行配置,把選擇權(quán)給到用戶,讓用戶通過配置來告訴你。甚至它可以不用用戶提供信息,可以自己來做數(shù)據(jù)收集,來評判這個方法是否應該被緩存起來。Uj028資訊網(wǎng)——每日最新資訊28at.com

但是,這玩意收益也不高啊。Uj028資訊網(wǎng)——每日最新資訊28at.com

本來泛化調(diào)用就不是 RPC 調(diào)用里面非常核心的東西,在這上面搞這么多心思,投入產(chǎn)出比不高啊。Uj028資訊網(wǎng)——每日最新資訊28at.com

有這時間,還不如想想主鏈路上還有沒有什么地方可以優(yōu)化優(yōu)化,在主鏈路上干事情,才是收益最大的事情。Uj028資訊網(wǎng)——每日最新資訊28at.com

就像是你在公司里面,在邊緣部門里面干得再出色,也很少能讓人注意到。但是如果你在核心部門里面,做出一點稍微亮眼的成績,大家都能看到。Uj028資訊網(wǎng)——每日最新資訊28at.com

所以,你以為你敲的只是代碼嗎?Uj028資訊網(wǎng)——每日最新資訊28at.com

不是的,你敲的,是人情世故。Uj028資訊網(wǎng)——每日最新資訊28at.com

最后,這個 pr 也合并到源碼中去了,再次查看這個類的提交記錄,你會發(fā)現(xiàn)一個熟悉的名稱:Uj028資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Uj028資訊網(wǎng)——每日最新資訊28at.com

說真的,刪除這三行代碼沒有任何技術含量,這部分代碼讓任何一個有 Java 基礎的人來看,都會發(fā)現(xiàn)這個問題。Uj028資訊網(wǎng)——每日最新資訊28at.com

我不過是在調(diào)試源碼的過程中撿了個漏而已。Uj028資訊網(wǎng)——每日最新資訊28at.com

但是為什么這部分代碼存在了很久時間了,是我撿到了這個漏呢?Uj028資訊網(wǎng)——每日最新資訊28at.com

我想,大概是我真的搭了個 Demo 然后一行行的跟了一下源碼吧。Uj028資訊網(wǎng)——每日最新資訊28at.com

所以,朋友,別只是看,要動手,說不定有意外收獲。Uj028資訊網(wǎng)——每日最新資訊28at.com

好了,價值也上完了,本文的技術部分就到這里啦。Uj028資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-35273-0.html我試圖通過這篇文章告訴你,什么是神奇的泛化調(diào)用。

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Python的三元表達式,你知道嗎?

下一篇: CSS:這幾個偽類,你用了嗎

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 和平县| 麻阳| 石台县| 佳木斯市| 山阴县| 阳原县| 哈密市| 雷波县| 通化市| 榕江县| 唐河县| 绥化市| 西藏| 临泉县| 荣昌县| 忻州市| 灵璧县| 宜宾县| 沙雅县| 集安市| 合水县| 唐海县| 句容市| 天长市| 新巴尔虎右旗| 萨嘎县| 玛曲县| 云阳县| 诸暨市| 留坝县| 新邵县| 克东县| 马公市| 灵宝市| 都昌县| 共和县| 贡山| 政和县| 犍为县| 依安县| 新郑市|