天天看點

SpringCloud之Feign(二)

       FeignClientsConfiguration初始化配置中:預設Encoder類型為SpringEncoder,功能為調用Spring的HttpMessageConverters處理參數。預設Decoder類型為ResponseEntityDecoder,它包裝了SpringDecoder,做的事情也就是調用Spring的HttpMessageConverters處理接口傳回值。預設Contract類型為SpringMvcContract,功能為解析SpringMvc的如RequestMapping、RequestParam、PathVariable等注解。預設日志類為DefaultFeignLoggerFactory,使用的是Slf4j,會為每個FeignClient建立一個Logger,列印各自的請求日志。

       FeignRibbonClientAutoConfiguration中最重的就是初始化Client執行個體,預設Client的類型為LoadBalancerFeignClient,它的預設通信方式是feign.Client.Default,其實就是HttpURLConnection,也可以修改為使用HttpClient或者OkHttp方式。Targeter預設實作類為HystrixTargeter,接口隻有一個方法為target,主要是調用Feign.Builder的target方法。Target中又調用build()方法生成ReflectiveFeign并調用ReflectiveFeign的newInstance生成最終執行個體。

       在ReflectiveFeign.newInstance中首先調用ParseHandlersByName.apply解析FeignClient的所有方法配置(使用Contract解析),并為的每個方法建立MethodHandler(預設實作為SynchronousMethodHandler),再把MethodHandler組合成一個InvocationHandler(預設實作為HystrixInvocationHandler),最後調用JDK的Proxy.newProxyInstance生成代理對象。

       當在項目中調用FeignClient的接口時,其實質是通過Proxy調用HystrixInvocationHandler.invoke方法建立HystrixCommand,并擷取到方法對應的SynchronousMethodHandler調用其invoke。在SynchronousMethodHandler的執行方法中,首先克隆一個RequestTemplate(由Contract解析而來)并填充真實參數值,然後生成的RequestTemplate經過RequestInterceptor的修改後,再由Target生成請求體Request。Feign會把Request交由Client(預設是LoadBalancerFeignClient)去進行HTTP請求,LoadBalancerFeignClient還進行了額外的軟負載。

       之前那篇《可靠性消息事務實作》一文中需要攔截FeignClient并擷取Request請求體。我的實作方式是從Client這裡下手,繼承LoadBalancerFeignClient重載其execute方法,判斷其是否包含在消息事務中,如果是則傳遞其Request,否則調用LoadBalancerFeignClient原有邏輯執行HTTP請求。我這裡判斷條件和Request傳遞都是通過ThreadLocal實作,看起來很奇怪,實則無奈。剛開始試過通過反射的方式,雖然可行,但比較複雜,涉及到較多對象。因為Feign代理的過程很多是不能擴充的,除非修改原碼(這樣侵入性太大,以後更新不利)。