偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

開(kāi)發(fā) 架構(gòu)
網(wǎng)關(guān)層提供一個(gè) API 接口發(fā)布平臺(tái),當(dāng)服務(wù)提供者的接口有新增或者發(fā)生變化的時(shí)候,由對(duì)應(yīng)系統(tǒng)的接口管理人員把接口信息,比如接口路徑、方法、入?yún)?、出參、方法功能說(shuō)明、方法負(fù)責(zé)團(tuán)隊(duì)、接口對(duì)接人等等這些消息維護(hù)到 API 接口發(fā)布平臺(tái)上。

你好呀,我是歪歪。

關(guān)于 RPC 調(diào)用,大家肯定都是比較熟悉的了,就是在微服務(wù)架構(gòu)下解決系統(tǒng)間通信問(wèn)題的一個(gè)玩意。

其中的典型代表之一就是 Dubbo 了:

圖片圖片

在微服務(wù)架構(gòu)下,我們針對(duì)某個(gè) RPC 接口,我們一般有兩個(gè)角色。

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

假設(shè)我是服務(wù)消費(fèi)者,想要調(diào)用某個(gè)服務(wù),只要我們鏈接到的是同一個(gè)服務(wù)注冊(cè)中心,那么找對(duì)應(yīng)服務(wù)要到 API 包對(duì)應(yīng)的 Maven 坐標(biāo),引入到項(xiàng)目中,就類(lèi)似于這樣的東西:

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

那么對(duì)于這個(gè) API 包中的接口,雖然我們沒(méi)有具體的實(shí)現(xiàn)類(lèi),但是我們還是能像調(diào)用本地方法一樣調(diào)用該服務(wù)提供的接口。

這些都是常規(guī)的東西了,你肯定是門(mén)清。

那我現(xiàn)在問(wèn)你一個(gè)問(wèn)題啊:

我是服務(wù)消費(fèi)者,我要調(diào)用一個(gè)服務(wù)提供者的 RPC 接口,但是我又不想引入它的 API 包,或者我根本就拉取不到它的 API 包,那么我應(yīng)該怎么辦?

如果你要非給我說(shuō):這不可能,既然是要消費(fèi)別人的接口,那么肯定要拿到 API 包才對(duì),你不拿就是你偷懶。

那我再給你舉個(gè)歪師傅在實(shí)際開(kāi)發(fā)過(guò)程中遇到的具體的例子:網(wǎng)關(guān)服務(wù)。

網(wǎng)關(guān)是個(gè)什么玩意?

是你對(duì)外請(qǐng)求的統(tǒng)一入口,做接受請(qǐng)求、分發(fā)請(qǐng)求用的,作為鏈接各個(gè)微服務(wù)的角色,你勢(shì)必要使用到下游的若干個(gè) RPC 服務(wù)。

你怎么辦?

引入所有的服務(wù)提供方的 API 包,然后發(fā)起調(diào)用嗎?

圖片圖片

可以是可以,但是不夠優(yōu)雅。

你想,如果有一個(gè)服務(wù)提供方發(fā)布了新的 API 包,你也需要更新版本,重新發(fā)版?

或者新來(lái)一個(gè)服務(wù)提供者 E,你需要引入其 API 包,然后重新發(fā)版?

網(wǎng)關(guān)應(yīng)該是一個(gè)穩(wěn)定的基礎(chǔ)服務(wù),它提供的是聚攏 API 接口、轉(zhuǎn)發(fā)調(diào)用的基礎(chǔ)功能,不應(yīng)該頻繁發(fā)版,不應(yīng)該主動(dòng)去關(guān)注下游的服務(wù)接口變化。平臺(tái)本身不應(yīng)該依賴(lài)于服務(wù)提供方的接口 API。

不主動(dòng),才能更加優(yōu)雅,也能讓自己更加輕松。

那么怎么才能做到不主動(dòng)關(guān)注呢?

這個(gè)事情,總有一方要主動(dòng)的,所以網(wǎng)關(guān)層不主動(dòng),那么服務(wù)提供者就需要主動(dòng)起來(lái)。

我們可以搞成這樣:

圖片圖片

網(wǎng)關(guān)層提供一個(gè) API 接口發(fā)布平臺(tái),當(dāng)服務(wù)提供者的接口有新增或者發(fā)生變化的時(shí)候,由對(duì)應(yīng)系統(tǒng)的接口管理人員把接口信息,比如接口路徑、方法、入?yún)?、出參、方法功能說(shuō)明、方法負(fù)責(zé)團(tuán)隊(duì)、接口對(duì)接人等等這些消息維護(hù)到 API 接口發(fā)布平臺(tái)上。

這樣網(wǎng)關(guān)層就可以從 API 接口發(fā)布平臺(tái)獲取到所有服務(wù)的所有接口,并不需要引入任何服務(wù)提供者的 API 包。

這樣就解決了“主動(dòng)”的問(wèn)題,如果接口有變化,請(qǐng)?jiān)?API 接口發(fā)布平臺(tái)進(jìn)行登記,從而解決了網(wǎng)關(guān)頻繁發(fā)布的問(wèn)題。

在官網(wǎng)上,除了網(wǎng)關(guān)的場(chǎng)景外,還提到一個(gè)測(cè)試平臺(tái)的場(chǎng)景,道理是一樣的,我就不贅述了:

https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/

圖片圖片

解決了“主動(dòng)”的問(wèn)題,那么下一個(gè)問(wèn)題就隨之而來(lái)了:知道所有服務(wù)的所有接口然后呢,怎么發(fā)起調(diào)用呢?

這個(gè)時(shí)候泛化調(diào)用,啪的一下就站出來(lái)了:鋪墊了這么多,終于該老子上場(chǎng)了。

泛化調(diào)用

啥是泛化調(diào)用呢?

在 Dubbo 官網(wǎng)上是這樣介紹的:

圖片圖片

首先需要強(qiáng)調(diào)的是“泛化調(diào)用”不是 Dubbo 特有的,它是一個(gè)功能,很多的框架都支持泛化調(diào)用,只是我這里用的 Dubbo 做演示而已。

老規(guī)矩,先花五分鐘時(shí)間搭個(gè) Demo 出來(lái)再說(shuō)。

這個(gè) Demo 我也是跟著網(wǎng)上的 quick start 搞的:

https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/spring-boot/

圖片圖片

可以說(shuō)寫(xiě)的非常詳細(xì)了,你就跟著官網(wǎng)的步驟一步步的搞就行了。

我這個(gè) Demo 稍微不一樣的是我在消費(fèi)者模塊里面搞了一個(gè) Http 接口:

圖片圖片

在接口里面發(fā)起了 RPC 調(diào)用,模擬從前端頁(yè)面發(fā)起請(qǐng)求的場(chǎng)景,更加符合我們的開(kāi)發(fā)習(xí)慣。

為了起到強(qiáng)調(diào)作用,我再次把這個(gè)部分給你框起來(lái):

圖片圖片

DemoService 是 RPC 接口,它的實(shí)現(xiàn)類(lèi)是這樣的:

圖片圖片

在我的消費(fèi)者模塊里面為什么能注入這個(gè) DemoService 并調(diào)用它的 sayHello 方法呢?

因?yàn)槲乙肓藢?duì)應(yīng)的依賴(lài)包。

那么,如果我把這個(gè)依賴(lài)包去掉,也就是模擬我們前面說(shuō)的“不主動(dòng)”的動(dòng)作,這個(gè) DemoService 肯定會(huì)報(bào)錯(cuò),找不到這個(gè)類(lèi):

圖片圖片

那么我們應(yīng)該怎么去修改一下這個(gè) Demo,讓它泛化起來(lái)呢?

非常簡(jiǎn)單:

圖片圖片

注入 DemoService 修改為注入 GenericService。

有的小伙伴可能會(huì)問(wèn) GenericService 是怎么冒出來(lái)的?

你先別管它是怎么冒出來(lái)的,我現(xiàn)在是在給你鋪墊 Demo,后面要撕給你看。你現(xiàn)在只需要知道它是 Dubbo 框架里面的包,并不會(huì)讓你引用額外的包就行了:

圖片圖片

現(xiàn)在 Demo 就算是搭好了,本地啟動(dòng)一個(gè) zk,然后把服務(wù)提供者啟動(dòng)起來(lái),再把消費(fèi)者啟動(dòng)起來(lái),最后輕輕的發(fā)起一個(gè)調(diào)用:

圖片圖片

朋友,它不就跑起來(lái)了嗎?

我沒(méi)有引用接口的 api 包,我不也正常發(fā)起了調(diào)用,然后拿到了返回值嗎?

啥原理

你就想,遠(yuǎn)程調(diào)用,你把一些花里胡哨的東西都拿掉之后,它的本質(zhì)是什么?

本質(zhì)就是幫助解決微服務(wù)組件之間的通信問(wèn)題,不管是基于  HTTP、HTTP/2、TCP 還是什么其他的通信協(xié)議,解決的是網(wǎng)絡(luò)連接管理、數(shù)據(jù)傳輸?shù)然A(chǔ)問(wèn)題。

雖然我沒(méi)有引用 API 的對(duì)應(yīng)的包,但是我前面我不是說(shuō)了嗎,我們有一個(gè) API 接口發(fā)布平臺(tái),這個(gè)平臺(tái)里面有接口維護(hù)人員提供的接口路徑、方法、入?yún)?、出參這些關(guān)鍵信息。

所以我在調(diào)用的時(shí)候可以拿到相關(guān)的信息,以一種通用的方式,比如字符串的方式告訴 RPC 框架,我要調(diào)用的是 DemoService 接口的 sayHello 方法,入?yún)⑹?String 類(lèi)型的 world 字符串:

如果是你來(lái)開(kāi)發(fā)一個(gè) RPC 框架,調(diào)用方都把這些關(guān)鍵信息給你了,無(wú)非就是你幫忙多做幾步類(lèi)似于反射、序列化之類(lèi)的處理。而處理的這個(gè)過(guò)程,就是泛化調(diào)用的過(guò)程。

泛化調(diào)用不是 Dubbo 特有的,但是具體到 Dubbo 這個(gè)框架里面,具體是這樣的。

首先,Dubbo 里面有一層 Filter,這些 Filter 構(gòu)成了一個(gè) Filter 鏈條:

圖片圖片

Filter 用來(lái)對(duì)每次服務(wù)調(diào)用做一些預(yù)處理、后處理動(dòng)作,使用 Filter 可以完成訪(fǎng)問(wèn)日志、加解密、流量統(tǒng)計(jì)、參數(shù)驗(yàn)證等任務(wù)。

一次請(qǐng)求過(guò)程中可以植入多個(gè) Filter,F(xiàn)ilter 之間相互獨(dú)立沒(méi)有依賴(lài)。

圖片圖片

從消費(fèi)端視角,它在請(qǐng)求發(fā)起前基于請(qǐng)求參數(shù)等做一些預(yù)處理工作,在接收到響應(yīng)后,對(duì)響應(yīng)結(jié)果做一些后置處理。

從提供者視角,在接收到訪(fǎng)問(wèn)請(qǐng)求后,在返回響應(yīng)結(jié)果前做一些預(yù)處理。

所以我們的泛化調(diào)用,也是通過(guò)下面這兩個(gè) Filter 來(lái)搞事情的:

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

那么問(wèn)題就來(lái)了?

為什么要兩個(gè) Filter 呢?

因?yàn)橐瓿梢淮畏夯{(diào)用,消費(fèi)端和服務(wù)提供者都需要感知到并做相關(guān)的處理,所以一個(gè)是消費(fèi)端的 Fliter,一個(gè)是服務(wù)提供者的 Fliter:

圖片圖片

圖片圖片

知道了對(duì)應(yīng)的 Filter,關(guān)于泛化調(diào)用的所有秘密都藏在 Filter 對(duì)應(yīng)的源碼里面。

歪師傅帶著你簡(jiǎn)單的看一眼。

GenericImplFilter.invoke

首先,我們?cè)诜椒ǖ南M(fèi)者對(duì)應(yīng)的 Fliter 的入口處打上斷點(diǎn):

org.apache.dubbo.rpc.filter.GenericImplFilter#invoke

可以看到分為了三個(gè)模塊。

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

我們研究的情況屬于 isMakingGenericCall 這個(gè)分支。

既然是要把泛化調(diào)用轉(zhuǎn)換為一個(gè)常規(guī)調(diào)用,那么 Dubbo 是怎么判斷這是一個(gè)泛化調(diào)用的呢?

org.apache.dubbo.rpc.filter.GenericImplFilter#isMakingGenericCall

圖片圖片

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

我們一個(gè)個(gè)的看。

或者invokeAsync 方法是 GenericService 這個(gè)接口里面的方法。而這兩個(gè)方法的入?yún)€(gè)數(shù)都是三個(gè)。

然后有個(gè) generic 參數(shù),在我的 Demo 里面這個(gè)參數(shù)是 true:

圖片圖片

當(dāng)我啪的一下跟進(jìn)到 isGeneric 方法中,才發(fā)現(xiàn)這里面別有洞天:

圖片圖片

原來(lái) generic 這個(gè)參數(shù)不只是可以為 “true”,它不同的值,代表著不同的序列化方式。

圖片圖片

通過(guò)這部分源碼可以看出來(lái),泛化調(diào)用對(duì)于客戶(hù)端,即在 GenericImplFilter 里面,并沒(méi)有做什么特別的操作,注意還是參數(shù)校驗(yàn)。

如果入?yún)⒑蛯?duì)應(yīng)的序列化方法不能匹配起來(lái),即使的拋出異常,這樣符合 Dubbo 框架的 fast-fail 思想。

但是其實(shí)看到這里的時(shí)候,我有一個(gè)小疑問(wèn),如果我寫(xiě)一個(gè)這樣的類(lèi):

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

和 GenericService 類(lèi)一樣,有 $invoke 方法,而且也是三個(gè)參數(shù)。

然后在上下文中塞個(gè) generic=true 進(jìn)去,那么是不是也能騙過(guò)這段代碼呢,也能進(jìn)入到 isMakingGenericCall 方法里面呢?

從代碼上看確實(shí)是這樣的,那么 Dubbo 到底是怎么規(guī)避這些“惡意”冒充者的呢?

我也不知道。

先存?zhèn)€疑吧,接著往下看。

GenericFilter.invoke

我們同樣在服務(wù)端打上斷點(diǎn),當(dāng)這個(gè)請(qǐng)求來(lái)到服務(wù)端的時(shí)候,我們?cè)倏纯捶?wù)端的情況。

org.apache.dubbo.rpc.filter.GenericFilter#invoke

可以看到這個(gè)方法邏輯都在 if 判斷為 true 的時(shí)候。

而這個(gè)判斷我們剛剛在客戶(hù)端已經(jīng)解析過(guò)了,只是多了一個(gè)判斷:

!GenericService.class.isAssignableFrom(invoker.getInterface())

看看發(fā)起調(diào)用的接口類(lèi)是不是 GenericService 類(lèi)的子類(lèi),如果是,則進(jìn)入到 if 分支里面。

朋友,這就有點(diǎn)意思了。幾秒鐘之前我們還在存疑,然后啪的一下疑問(wèn)就解開(kāi)了。

直接就是恍然大悟了。

我這個(gè)類(lèi):

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

過(guò)不了服務(wù)提供者的 GenericFilter 里面的這個(gè)判斷:

!GenericService.class.isAssignableFrom(invoker.getInterface())

在 invoke 方法里面,可以看到經(jīng)過(guò)了一個(gè) findMethodByMethodSignature 方法,獲取了我們想要調(diào)用的 method 方法:

圖片圖片

這個(gè)方法,從名字上也可以看出,是根據(jù)方法簽名反射出具體的方法:

圖片圖片

在服務(wù)端,是有 DemoService 接口對(duì)應(yīng)的類(lèi)的,所以可以通過(guò)反射找到它。

然后再解析出入?yún)⒌木唧w值:

圖片圖片

這樣你就有了構(gòu)建一個(gè) RpcInvocation 對(duì)象,即發(fā)起 RPC 調(diào)用的對(duì)象的所有關(guān)鍵消息。

直接就是發(fā)動(dòng)一招“貍貓換太子”的大動(dòng)作,重新構(gòu)建一個(gè) RpcInvocation 對(duì)象,然后自己發(fā)起一個(gè) invoke 調(diào)用。

圖片圖片

這樣整體看起來(lái)似乎一次泛化調(diào)用也是很簡(jiǎn)單的,當(dāng)你去看服務(wù)提供端的源碼的時(shí)候,你會(huì)發(fā)現(xiàn)這里面的源碼特別多。

不過(guò)是因?yàn)?Dubbo 支持了多種不同的序列化方式而已,本質(zhì)是一樣的:

圖片圖片

onResponse 方法也是同理,就不贅述了:

org.apache.dubbo.rpc.filter.GenericFilter#onResponse

圖片圖片

到這里就算是扯下了泛化調(diào)用的神秘面紗,和我們預(yù)想的一樣,無(wú)非是拿到接口調(diào)用的關(guān)鍵信息之后,重新構(gòu)建一個(gè)請(qǐng)求而已,整體邏輯并不復(fù)雜。

復(fù)雜的邏輯是什么?

我演示的是最簡(jiǎn)單的,入?yún)⑹且粋€(gè) String 類(lèi)型的情況。如果我是一個(gè)復(fù)雜對(duì)象呢,對(duì)象里面的成員變量特別多,對(duì)象里面套對(duì)象,對(duì)象里面有 List 或者 Map 的情況呢?

復(fù)雜的地方在于怎么處理這些復(fù)雜對(duì)象,把復(fù)雜對(duì)象搞成服務(wù)提供者的 Java 對(duì)象入?yún)ⅰ?/p>

我這里只是一個(gè)導(dǎo)讀而已,如果你對(duì)這部分有興趣的話(huà),自己搞個(gè)復(fù)雜對(duì)象去研究研究吧,老有意思了。

就當(dāng)是家庭作業(yè)了。

意外收獲

歪師傅在扯面紗的時(shí)候,沒(méi)想到還有意外收獲。

給你看一段代碼,也是前面出現(xiàn)過(guò)的一個(gè)方法,我把完整的代碼都截圖放出來(lái):

org.apache.dubbo.common.utils.ReflectUtils#findMethodByMethodSignature

圖片圖片

你瞅瞅我框起來(lái)部分的 signature 字段,是不是沒(méi)有任何卵用?

自信一點(diǎn),不要懷疑,確實(shí)沒(méi)有任何用處,signature 只是賦了個(gè)值而已,后續(xù)的代碼中并沒(méi)有使用。

所以,我小腦瓜子一轉(zhuǎn),立刻察覺(jué)到這又是一個(gè)水 pr 的好機(jī)會(huì)。

于是...

https://github.com/apache/dubbo/pull/13382

圖片圖片

晚上 10 點(diǎn)半的時(shí)候,直接就是一個(gè)貢獻(xiàn)源碼的大動(dòng)作,小手一揮,帶走四行代碼:

圖片圖片

當(dāng)時(shí)我沒(méi)細(xì)想,但是后來(lái)躺在床上的時(shí)候我突然想起來(lái):不應(yīng)該啊,這個(gè)地方為什么會(huì)留著幾行看起來(lái)是沒(méi)有刪除不干凈的代碼呢?

隱隱覺(jué)得這里面應(yīng)該是有故事的。

于是看了這個(gè)類(lèi)的提交記錄,主要找兩個(gè)地方:這個(gè) signature 是什么時(shí)候有的,又是什么時(shí)候沒(méi)的。

在 2012 年 6 月 15 日,針對(duì)這個(gè)類(lèi)做了一次性能優(yōu)化:

圖片圖片

優(yōu)化的具體內(nèi)容就是用 Map 把方法緩存起來(lái),以免每次都需要去走反射的邏輯。

圖片圖片

圖片圖片

看完這個(gè)提交之后我覺(jué)得很合理啊,使用 Map 緩存一下確實(shí)屬于性能優(yōu)化。

那么為什么又把這個(gè) Map 拿走了呢?

于是我在 2021 年 9 月 6 日的提交中找到了拿走 Map 對(duì)應(yīng)的提交記錄:

圖片圖片

圖片圖片

這次提交的內(nèi)容非常的多,而從提交記錄的 log 中并沒(méi)有找到為什么要移除這個(gè) Map 的原因:

圖片圖片

怎么辦?

很簡(jiǎn)單,社區(qū)提問(wèn)就行了。

于是我在我的 pr 下面拋出了自己的問(wèn)題:

圖片圖片

我查看了該類(lèi)的提交歷史,發(fā)現(xiàn) #8684 刪除了 ReflectUtils.java 中的所有 Map 緩存,遺留了對(duì) signature  字段的處理。
但是我不明白為什么要?jiǎng)h除緩存,在我看來(lái)應(yīng)該保留緩存。能說(shuō)一下官方是怎么考慮的嗎?

很快我就得到了官方的回復(fù):

圖片圖片

刪除緩存的原因是因?yàn)檫@些 Map 緩存是全局變量,這會(huì)導(dǎo)致從 Dubbo 的類(lèi)(通常是 GC root)到對(duì)應(yīng)類(lèi)的引用,而這些類(lèi)在 ClassLoader 被閑置后無(wú)法釋放。

啥意思呢?

我大概的解釋一下。

首先,我們看一下這個(gè) Map 的定義是怎么樣的:

private static final ConcurrentMap<String, Method> SIGNATURE_METHODS_CACHE = new ConcurrentHashMap<String, Method>();

它是個(gè) static 對(duì)象,那么它是不是會(huì)被作為一個(gè) GC root?

如果它作為一個(gè) GC root,它里面緩存的這些方法,是不是都是“可達(dá)的”?

方法是可達(dá)的,那么這些方法對(duì)應(yīng)的 Class 類(lèi)是不是也是“可達(dá)的”?

但是在這些方法對(duì)應(yīng)的 Class 類(lèi)的 ClassLoader 完成自己的使命,被回收之后,那么這個(gè) Class 類(lèi)是不是理論上也可以被回收了?

但是實(shí)際情況是什么呢?

實(shí)際情況是因?yàn)檫@個(gè) static 對(duì)象還持有其引用,導(dǎo)致它不會(huì)被回收。

基于這個(gè)考慮,官方?jīng)Q定移除這個(gè) Map。

其實(shí)我個(gè)人覺(jué)得,如果我上面的理解沒(méi)有錯(cuò)的話(huà),那么討論這個(gè) Map 的效果,可以得兩個(gè)分情況:

如果一個(gè)泛化調(diào)用的調(diào)用頻率非常低,那么你把對(duì)應(yīng)的方法緩存起來(lái),導(dǎo)致 GC 一直回收不了,確實(shí)沒(méi)啥意思。

如果一個(gè)泛化調(diào)用的調(diào)用頻率比較高,那么你把對(duì)應(yīng)的方法緩存起來(lái),確實(shí)能起到“性能優(yōu)化”的效果。

那么 Dubbo 作為一個(gè)框架怎么知道你的這個(gè)方法調(diào)用的頻率高不高呢?

它也不知道,所以干脆不要替用戶(hù)多做這一步,做多了,反而容易出錯(cuò)。

其實(shí)它也是可以知道的,比如可以提供一個(gè)參數(shù)給用戶(hù)進(jìn)行配置,把選擇權(quán)給到用戶(hù),讓用戶(hù)通過(guò)配置來(lái)告訴你。甚至它可以不用用戶(hù)提供信息,可以自己來(lái)做數(shù)據(jù)收集,來(lái)評(píng)判這個(gè)方法是否應(yīng)該被緩存起來(lái)。

但是,這玩意收益也不高啊。

本來(lái)泛化調(diào)用就不是 RPC 調(diào)用里面非常核心的東西,在這上面搞這么多心思,投入產(chǎn)出比不高啊。

有這時(shí)間,還不如想想主鏈路上還有沒(méi)有什么地方可以?xún)?yōu)化優(yōu)化,在主鏈路上干事情,才是收益最大的事情。

就像是你在公司里面,在邊緣部門(mén)里面干得再出色,也很少能讓人注意到。但是如果你在核心部門(mén)里面,做出一點(diǎn)稍微亮眼的成績(jī),大家都能看到。

所以,你以為你敲的只是代碼嗎?

不是的,你敲的,是人情世故。

最后,這個(gè) pr 也合并到源碼中去了,再次查看這個(gè)類(lèi)的提交記錄,你會(huì)發(fā)現(xiàn)一個(gè)熟悉的名稱(chēng):

圖片圖片

說(shuō)真的,刪除這三行代碼沒(méi)有任何技術(shù)含量,這部分代碼讓任何一個(gè)有 Java 基礎(chǔ)的人來(lái)看,都會(huì)發(fā)現(xiàn)這個(gè)問(wèn)題。

我不過(guò)是在調(diào)試源碼的過(guò)程中撿了個(gè)漏而已。

但是為什么這部分代碼存在了很久時(shí)間了,是我撿到了這個(gè)漏呢?

我想,大概是我真的搭了個(gè) Demo 然后一行行的跟了一下源碼吧。

所以,朋友,別只是看,要?jiǎng)邮郑f(shuō)不定有意外收獲。

好了,價(jià)值也上完了,本文的技術(shù)部分就到這里啦。

責(zé)任編輯:武曉燕 來(lái)源: why技術(shù)
相關(guān)推薦

2023-04-24 08:39:01

閱讀源碼方式

2020-07-09 10:21:03

網(wǎng)絡(luò)排錯(cuò)TCPIP

2020-02-12 18:55:24

負(fù)載因子初始值為什么

2018-02-08 18:16:39

數(shù)據(jù)庫(kù)MySQL鎖定機(jī)制

2020-09-18 10:18:08

MySQL數(shù)據(jù)插入數(shù)據(jù)庫(kù)

2023-04-06 11:10:31

閉包JavaScript

2021-04-16 16:37:23

SpringMVC源碼配置

2019-01-08 07:43:53

路由器調(diào)制解調(diào)器

2024-04-23 08:23:36

TypeScript泛型Generics

2024-04-12 00:00:00

localhost計(jì)算機(jī)機(jī)制

2021-03-14 10:24:21

HashMap負(fù)載初始值

2019-09-02 09:06:04

無(wú)線(xiàn)路由器光貓WiFi

2020-05-06 19:47:15

人工智能AI

2020-12-10 13:46:35

人工智能

2023-12-24 22:42:57

數(shù)據(jù)庫(kù)分片中間件

2019-01-28 11:24:53

Windows 功能系統(tǒng)

2017-07-12 16:56:42

卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)數(shù)據(jù)CNN

2017-07-05 15:42:58

卷積神經(jīng)網(wǎng)絡(luò)Non-Euclide計(jì)算機(jī)視覺(jué)

2017-03-30 22:41:55

虛擬化操作系統(tǒng)軟件

2019-01-30 13:44:34

JVM內(nèi)存服務(wù)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)