SOFA 源碼分析 — 泛化調用

前言

通常 RPC 調用需要客戶端使用服務端提供的接口,而具體的形式則是使用 jar 包,通過引用 jar 包獲取接口的的具體信息,例如接口名稱,方法名稱,參數(shù)類型,返回值類型。

但也存在一些情況,例如客戶端沒有 jar 包,或者是跨語言的調用,這個時候,就需要客戶端使用字符串進行泛化調用。

如何使用

還是根據(jù)官方的例子來看一下:

ConsumerConfig<GenericService> consumerConfig = new ConsumerConfig<GenericService>()
           .setInterfaceId("com.alipay.sofa.rpc.quickstart.HelloService")
           .setGeneric(true);
GenericService testService = consumerConfig.refer();

String result = (String) testService.$invoke("sayHello", new String[] { "java.lang.String" },new Object[] { "1111" });

我們看到,實際上,設置接口 ID 是和普通的調用時類似的,只是需要增加一個 Generic 屬性為 true。

然后就返回了一個 GenericService 類型的代理對象,通過這個對象,就可以對服務發(fā)起調用,而調用的方式,則是使用 GenericService 的 $invoke 方法,需要傳遞方法名稱,參數(shù)類型,參數(shù)值。并指定返回值。

SOFA 是如何實現(xiàn)的呢?

源碼實現(xiàn)

既然和普通的調用只是變化了 Generic 屬性,那么,我們就看看這個屬性在哪些地方使用。

我們很快便找到了一個過濾器: ConsumerGenericFilter,該過濾器的生效條件則是 “客戶端是否配置了泛型”。如果設置泛型,則添加到過濾鏈中。

而該過濾器的 invoke 方法肯定是對調用進行了一些特殊的操作,具體如下:

  1. 根據(jù)方法名稱得到序列化的類型,例如普通序列化,泛型序列化,混合序列化。我們這里的例子返回的值是 0(普通序列化),然后設置序列化工廠類型,即普通序列化(根據(jù)方法名不同而不同)。
  2. 從 Request 對象中拿到方法名稱,參數(shù)類型的字符串,方法參數(shù)。并重新設置到 Request 對象中,相當于重新整理了一遍。
  3. 然后根據(jù)剛剛設置的方法名重新設置調用類型。

這樣就將泛型的調用修改成和普通調用一樣了。
同時注意:發(fā)起調用時,該過濾器的默認 order 是 -18000,因此他會在大部分(除了異常處理和上下文)之前執(zhí)行。

在使用 Bolt 的 RpcClient 進行調用的時候,會根據(jù)序列化類型決定是否進行泛型的序列化。

具體過程是,當調用時,會創(chuàng)建 InvokeContext 上下文,會在 Map 中存儲自定義的序列化器,其中 key 是 SerializeFactoryType,value 是 0(我們這里),在 RpcRemoting 的 invokeXXX 方法中,會創(chuàng)建一個 RemotingCommand 對象,即執(zhí)行 toRemotingCommand 方法,根據(jù) InvokeContext 中的 SerializeFactoryType 獲取到序列化工廠的枚舉值,并設置到 RemotingCommand 對象中。

在 SofaRpcSerialization 類中,會根據(jù) invokeContext 中存儲的序列化枚舉值得到序列化器,具體代碼如下:

// 根據(jù)SerializeType信息決定序列化器
boolean genericSerialize = genericSerializeRequest(invokeContext);
if (genericSerialize) {
    output.setSerializerFactory(genericSerializerFactory);
} else {
    output.setSerializerFactory(serializerFactory);
}

根據(jù)SerializeType信息決定序列化器。而泛型的具體序列化器工廠則是 GenericMultipleClassLoaderSofaSerializerFactory 類,該類的會生成序列化器和反序列化器。并在 Bolt 中使用。

總結

從 SOFA 的設計中可以看出,泛化調用主要依賴于 GenericService 這個類和對應的 ConsumerGenericFilter 過濾器,如果一個客戶端設置泛化了,那么調用過程中則會啟用這個過濾器。

這個過濾器會將請求的數(shù)據(jù)重新整理。并修改成普通調用的樣子。

同時也會設置一個泛型調用的序列化枚舉放置在上下文中,上下文在 Bolt 中會根據(jù)枚舉值動態(tài)獲取不同的序列化器和反序列化器,對輸出參數(shù)和返回值經進行處理。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,597評論 19 139
  • 一、基礎知識:1、JVM、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機...
    殺小賊閱讀 2,569評論 0 4
  • 內心充滿歡喜,才能把歡喜給別人;內心蘊藏著無限的慈悲,才能把慈悲傳遞出去,因為舍什么就會得什么,這是必然的因果。 ???
    曇花舞閱讀 104評論 0 0
  • 在鄉(xiāng)下走夜路,你有過幾次? 那種刺激!那種驚悚!現(xiàn)在都怕想。 午夜:走在鄉(xiāng)間小路上 很久很久前,月黑風...
    天河水響閱讀 1,035評論 8 13

友情鏈接更多精彩內容