天天看点

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代理的过程很多是不能扩展的,除非修改原码(这样侵入性太大,以后升级不利)。