SpringCloudRPC遠(yuǎn)程調(diào)用核心原理:Feign遠(yuǎn)程調(diào)用的執(zhí)行流程
Feign遠(yuǎn)程調(diào)用的執(zhí)行流程
由于Feign中生成RPC接口JDK動態(tài)代理實(shí)例涉及的InvocationHandler調(diào)用處理器有多種,導(dǎo)致Feign遠(yuǎn)程調(diào)用的執(zhí)行流程稍微有所區(qū)別,但是遠(yuǎn)程調(diào)用執(zhí)行流程的主要步驟是一致的。這里主要介紹與兩類InvocationHandler調(diào)用處理器相關(guān)的RPC執(zhí)行流程:
(1)與默認(rèn)的調(diào)用處理器FeignInvocationHandler相關(guān)的RPC執(zhí)行流程。
(2)與Hystrix調(diào)用處理器HystrixInvocationHandler相關(guān)的RPC執(zhí)行流程。
還是以uaa-provider啟動過程中的DemoClient接口的動態(tài)代理實(shí)例的執(zhí)行過程為例演示和分析遠(yuǎn)程調(diào)用的執(zhí)行流程。
與FeignInvocationHandler相關(guān)的遠(yuǎn)程調(diào)用執(zhí)行流程
FeignInvocationHandler是默認(rèn)的調(diào)用處理器,如果進(jìn)行特殊的配置,那么Feign將默認(rèn)使用此調(diào)用處理器。
結(jié)合uaa-provider服務(wù)中DemoClient的動態(tài)代理實(shí)例的hello()方法遠(yuǎn)程調(diào)用執(zhí)行過程,這里詳細(xì)介紹與FeignInvocationHandler相關(guān)的遠(yuǎn)程調(diào)用執(zhí)行流程,如圖3-25所示。

圖3-25 與FeignInvocationHandler相關(guān)的遠(yuǎn)程調(diào)用執(zhí)行流程
整體的遠(yuǎn)程調(diào)用執(zhí)行流程大致分為4步,具體如下:
(1)通過Spring IOC容器實(shí)例完成動態(tài)代理實(shí)例的裝配。
前文講到,F(xiàn)eign在啟動時會為加上了@FeignClient注解的所有遠(yuǎn)程接口(包括DemoClient接口)創(chuàng)建一個FactoryBean工廠實(shí)例,并注冊到Spring IOC容器。然后在uaa-provider的DemoRPCController控制層類中,通過@Resource注解從Spring IOC容器找到FactoryBean工廠實(shí)例,通過其getObject()方法獲取到動態(tài)代理實(shí)例,裝配給DemoRPCController實(shí)例的成員變量demoClient。
在需要進(jìn)行hello()遠(yuǎn)程調(diào)用時,直接通過demoClient成員變量調(diào)用JDK動態(tài)代理實(shí)例的hello()方法。
(2)執(zhí)行InvocationHandler調(diào)用處理器的invoke(...)方法。
前面講到,JDK動態(tài)代理實(shí)例的方法調(diào)用過程是通過委托給InvocationHandler調(diào)用處理器完成的,故在調(diào)用demoClient的hello()方法時,會調(diào)用到它的調(diào)用處理器FeignInvocationHandler實(shí)例的invoke(...)方法。
大家知道,F(xiàn)eignInvocationHandler實(shí)例內(nèi)部保持了一個遠(yuǎn)程調(diào)用方法反射實(shí)例和方法處理器的dispatch映射。FeignInvocationHandle在它的invoke(...)方法中會根據(jù)hello()方法的Java反射實(shí)例在dispatch映射對象中找到對應(yīng)的MethodHandler方法處理器,然后由后者完成實(shí)際的HTTP請求和結(jié)果的處理。
(3)執(zhí)行MethodHandler方法處理器的invoke(...)方法。
通過前面關(guān)于MethodHandler方法處理器的組件介紹,大家都知道,feign默認(rèn)的方法處理器為SynchronousMethodHandler同步調(diào)用處理器,它的invoke(...)方法主要通過內(nèi)部feign。Client類型的client成員實(shí)例完成遠(yuǎn)程URL請求執(zhí)行和獲取遠(yuǎn)程結(jié)果。
feign.Client客戶端有多種類型,不同的類型完成URL請求處理的具體方式不同。(4)通過feign.Client客戶端成員完成遠(yuǎn)程URL請求執(zhí)行和獲取遠(yuǎn)程結(jié)果。
如果MethodHandler方法處理器client成員實(shí)例是默認(rèn)的feign.Client.Default實(shí)現(xiàn)類,就通過JDK自帶的HttpURLConnnection類完成遠(yuǎn)程URL請求執(zhí)行和獲取遠(yuǎn)程結(jié)果。
如果MethodHandler方法處理器實(shí)例的client客戶端是ApacheHttpClient客戶端實(shí)現(xiàn)類,就使用ApacheHttpClient開源組件完成遠(yuǎn)程URL請求執(zhí)行和獲取遠(yuǎn)程結(jié)果。
如果MethodHandler方法處理器實(shí)例的client客戶端是LoadBalancerFeignClient負(fù)載均衡客戶端實(shí)現(xiàn)類,就使用Ribbon結(jié)算出最佳的Provider節(jié)點(diǎn),然后由內(nèi)部的delegate委托客戶端成員去請求Provider服務(wù),完成URL請求處理。
以上4步基本上就是Spring Cloud中的Feign遠(yuǎn)程調(diào)用的執(zhí)行流程。
然而,默認(rèn)的基于FeignInvocationHandler調(diào)用處理器的執(zhí)行流程在運(yùn)行機(jī)制和調(diào)用性能上都滿足不了生產(chǎn)環(huán)境的要求,大致原因有以下兩點(diǎn):
(1)在遠(yuǎn)程調(diào)用過程中沒有異常的熔斷監(jiān)測和恢復(fù)機(jī)制。
(2)沒有用到高性能的HTTP連接池技術(shù)。
接下來將為大家介紹一種結(jié)合Hystrix進(jìn)行RPC保護(hù)的遠(yuǎn)程調(diào)用處理流程。在該流程中所使用的InvocationHandler調(diào)用處理器叫作HystrixInvocationHandler調(diào)用處理器。
這里作為鋪墊,首先為大家介紹HystrixInvocationHandler調(diào)用處理器本身的具體實(shí)現(xiàn)。
?與HystrixInvocationHandler相關(guān)的遠(yuǎn)程調(diào)用執(zhí)行流程
HystrixInvocationHandler調(diào)用處理器類位于feign.hystrix包中,其字節(jié)碼文件不是處于feign核心包feign-core-*.jar中,而是在擴(kuò)展包feignhystrix-*.jar中。這里的*表示的是與Spring Cloud版本配套的版本號,當(dāng)Spring Cloud的版本為Finchley.RELEASE時,feign-core和feign-hystrix兩個JAR包的版本號都為9.5.1。
HystrixInvocationHandler是具備RPC保護(hù)能力的調(diào)用處理器,它實(shí)現(xiàn)了InvocationHandler接口,對接口的invoke(...)抽象方法的實(shí)現(xiàn)如下:
package feign.hystrix;
//省略import
final class HystrixInvocationHandler implements InvocationHandler {
...
//... Map映射:Key為RPC方法的反射實(shí)例,value為方法處理器
private final Map dispatch;
...
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
//創(chuàng)建一個HystrixCommand命令,對同步方法調(diào)用器進(jìn)行封裝
HystrixCommand HystrixInvocationHandler調(diào)用處理器與默認(rèn)調(diào)用處理器FeignInvocationHandler有一個共同點(diǎn):都有一個非常重要的Map類型成員dispatch映射,保存著RPC方法反射實(shí)例到MethodHandler方法處理器的映射。
在源碼中,HystrixInvocationHandler的invoke(...)方法會創(chuàng)建hystrixCommand命令實(shí)例,對從dispatch獲取的SynchronousMethodHandler實(shí)例進(jìn)行封裝,然后對RPC方法實(shí)例method進(jìn)行判斷,判斷是直接返回hystrixCommand命令實(shí)例,還是立即執(zhí)行其execute()方法。默認(rèn)情況下,都是立即執(zhí)行它的execute()方法。
HystrixCommand具備熔斷、隔離、回退等能力,如果它的run()方法執(zhí)行發(fā)生異常,就會執(zhí)行g(shù)etFallback()失敗回調(diào)方法,這一點(diǎn)后面會詳細(xì)介紹。
回到uaa-provider服務(wù)中DemoClient動態(tài)代理實(shí)例的hello()方法的具體執(zhí)行過程,在執(zhí)行命令處理器hystrixCommand實(shí)例的run()方法時,步驟如下:
(1)根據(jù)RPC方法DemoClient.hello()的反射實(shí)例在dispatch映射對象中找到對應(yīng)的方法處理器MethodHandler實(shí)例。
(2)調(diào)用MethodHandler方法處理器的invoke(...)方法完成實(shí)際的hello()方法所配置的遠(yuǎn)程URL的HTTP請求和結(jié)果的處理。
如果MethodHandler內(nèi)的RPC調(diào)用出現(xiàn)異常,比如遠(yuǎn)程server宕機(jī)、網(wǎng)絡(luò)延遲太大而導(dǎo)致請求超時、遠(yuǎn)程server來不及響應(yīng)等,hystrixCommand命令器就會調(diào)用失敗回調(diào)方法getFallback()返回回退結(jié)果。
而hystrixCommand的getFallback()方法最終會調(diào)用配置在RPC接口@FeignClient注解的fallback屬性上的失敗回退類中對應(yīng)的回退方法,執(zhí)行業(yè)務(wù)級別的失敗回退處理。
使用HystrixInvocationHandler方法處理器進(jìn)行遠(yuǎn)程調(diào)用,總體流程與使用默認(rèn)的方法處理器FeignInvocationHandler進(jìn)行遠(yuǎn)程調(diào)用大致是相同的。
以uaa-provider模塊的DemoClient中hello()方法的遠(yuǎn)程調(diào)用執(zhí)行過程為例,進(jìn)行整體流程的展示,具體的時序圖如圖3-26所示。

圖3-26 與HystrixInvocationHandler相關(guān)的遠(yuǎn)程調(diào)用執(zhí)行流程
總體來說,使用HystrixInvocationHandler處理器的執(zhí)行流程與使用FeignInvocationHandler默認(rèn)的調(diào)用處理器相比大致是相同的。不同的是,HystrixInvocationHandler增加了RPC的保護(hù)機(jī)制。
Feign遠(yuǎn)程調(diào)用的完整流程及其特性
Feign是一個聲明式的RPC調(diào)用組件,它整合了Ribbon和Hystrix,使得服務(wù)調(diào)用更加簡單。Feign提供了HTTP請求的模板,通過編寫簡單的接口和方法注解就可以定義好HTTP請求的參數(shù)、格式、地址等信息。
Feign極大地簡化了RPC遠(yuǎn)程調(diào)用,大家只需要像調(diào)用普通方法一樣就可以完成RPC遠(yuǎn)程調(diào)用。
Feign遠(yuǎn)程調(diào)用的核心是通過一系列封裝和處理,將以JAVA注解方式定義的RPC方法最終轉(zhuǎn)換成HTTP請求,然后將HTTP請求的響應(yīng)結(jié)果解碼成POJO對象返回給調(diào)用者。
Feign遠(yuǎn)程調(diào)用的完整流程如圖3-27所示。

圖3-27 Feign遠(yuǎn)程調(diào)用的完整流程
從圖3-27可以看到,F(xiàn)eign通過對RPC注解的解析將請求模板化。當(dāng)實(shí)際調(diào)用時傳入?yún)?shù),再根據(jù)參數(shù)應(yīng)用到請求模板上,進(jìn)而轉(zhuǎn)化成真正的Request請求。通過Feign及其動態(tài)代理機(jī)制,Java開發(fā)人員不用再通過HTTP框架封裝HTTP請求報文的方式完成遠(yuǎn)程服務(wù)的HTTP調(diào)用。
Spring Cloud Feign具有如下特性:
(1)可插拔的注解支持,包括Feign注解和Spring MVC注解。
(2)支持可插拔的HTTP編碼器和解碼器。
(3)支持Hystrix和它的RPC保護(hù)機(jī)制。
(4)支持Ribbon的負(fù)載均衡。
(5)支持HTTP請求和響應(yīng)的壓縮。
總體來說,使用Spring Cloud Feign組件本身整合了Ribbon和Hystrix,可設(shè)計一套穩(wěn)定可靠的彈性客戶端調(diào)用方案,避免整個系統(tǒng)出現(xiàn)雪崩效應(yīng)。
本文給大家講解的內(nèi)容是SpringCloudRPC遠(yuǎn)程調(diào)用核心原理:Feign遠(yuǎn)程調(diào)用的執(zhí)行流程
下篇文章給大家講解的是SpringCloudRPC遠(yuǎn)程調(diào)用核心原理:HystrixFeign動態(tài)代理實(shí)例的創(chuàng)建流程;
覺得文章不錯的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;
感謝大家的支持!
本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學(xué)習(xí)更多的話可以到微信公眾號里找我,我等你哦。
