SpringCloudRPC远程调用核心原理:Feign远程调用的执行流程
Feign远程调用的执行流程
由于Feign中生成RPC接口JDK动态代理实例涉及的InvocationHandler调用处理器有多种,导致Feign远程调用的执行流程稍微有所区别,但是远程调用执行流程的主要步骤是一致的。这里主要介绍与两类InvocationHandler调用处理器相关的RPC执行流程:
(1)与默认的调用处理器FeignInvocationHandler相关的RPC执行流程。
(2)与Hystrix调用处理器HystrixInvocationHandler相关的RPC执行流程。
还是以uaa-provider启动过程中的DemoClient接口的动态代理实例的执行过程为例演示和分析远程调用的执行流程。
与FeignInvocationHandler相关的远程调用执行流程
FeignInvocationHandler是默认的调用处理器,如果进行特殊的配置,那么Feign将默认使用此调用处理器。
结合uaa-provider服务中DemoClient的动态代理实例的hello()方法远程调用执行过程,这里详细介绍与FeignInvocationHandler相关的远程调用执行流程,如图3-25所示。
图3-25 与FeignInvocationHandler相关的远程调用执行流程
整体的远程调用执行流程大致分为4步,具体如下:
(1)通过Spring IOC容器实例完成动态代理实例的装配。
前文讲到,Feign在启动时会为加上了@FeignClient注解的所有远程接口(包括DemoClient接口)创建一个FactoryBean工厂实例,并注册到Spring IOC容器。然后在uaa-provider的DemoRPCController控制层类中,通过@Resource注解从Spring IOC容器找到FactoryBean工厂实例,通过其getObject()方法获取到动态代理实例,装配给DemoRPCController实例的成员变量demoClient。
在需要进行hello()远程调用时,直接通过demoClient成员变量调用JDK动态代理实例的hello()方法。
(2)执行InvocationHandler调用处理器的invoke(...)方法。
前面讲到,JDK动态代理实例的方法调用过程是通过委托给InvocationHandler调用处理器完成的,故在调用demoClient的hello()方法时,会调用到它的调用处理器FeignInvocationHandler实例的invoke(...)方法。
大家知道,FeignInvocationHandler实例内部保持了一个远程调用方法反射实例和方法处理器的dispatch映射。FeignInvocationHandle在它的invoke(...)方法中会根据hello()方法的Java反射实例在dispatch映射对象中找到对应的MethodHandler方法处理器,然后由后者完成实际的HTTP请求和结果的处理。
(3)执行MethodHandler方法处理器的invoke(...)方法。
通过前面关于MethodHandler方法处理器的组件介绍,大家都知道,feign默认的方法处理器为SynchronousMethodHandler同步调用处理器,它的invoke(...)方法主要通过内部feign。Client类型的client成员实例完成远程URL请求执行和获取远程结果。
feign.Client客户端有多种类型,不同的类型完成URL请求处理的具体方式不同。(4)通过feign.Client客户端成员完成远程URL请求执行和获取远程结果。
如果MethodHandler方法处理器client成员实例是默认的feign.Client.Default实现类,就通过JDK自带的HttpURLConnnection类完成远程URL请求执行和获取远程结果。
如果MethodHandler方法处理器实例的client客户端是ApacheHttpClient客户端实现类,就使用ApacheHttpClient开源组件完成远程URL请求执行和获取远程结果。
如果MethodHandler方法处理器实例的client客户端是LoadBalancerFeignClient负载均衡客户端实现类,就使用Ribbon结算出最佳的Provider节点,然后由内部的delegate委托客户端成员去请求Provider服务,完成URL请求处理。
以上4步基本上就是Spring Cloud中的Feign远程调用的执行流程。
然而,默认的基于FeignInvocationHandler调用处理器的执行流程在运行机制和调用性能上都满足不了生产环境的要求,大致原因有以下两点:
(1)在远程调用过程中没有异常的熔断监测和恢复机制。
(2)没有用到高性能的HTTP连接池技术。
接下来将为大家介绍一种结合Hystrix进行RPC保护的远程调用处理流程。在该流程中所使用的InvocationHandler调用处理器叫作HystrixInvocationHandler调用处理器。
这里作为铺垫,首先为大家介绍HystrixInvocationHandler调用处理器本身的具体实现。
与HystrixInvocationHandler相关的远程调用执行流程
HystrixInvocationHandler调用处理器类位于feign.hystrix包中,其字节码文件不是处于feign核心包feign-core-*.jar中,而是在扩展包feignhystrix-*.jar中。这里的*表示的是与Spring Cloud版本配套的版本号,当Spring Cloud的版本为Finchley.RELEASE时,feign-core和feign-hystrix两个JAR包的版本号都为9.5.1。
HystrixInvocationHandler是具备RPC保护能力的调用处理器,它实现了InvocationHandler接口,对接口的invoke(...)抽象方法的实现如下:
package feign.hystrix;
//省略import
final class HystrixInvocationHandler implements InvocationHandler {
...
//... Map映射:Key为RPC方法的反射实例,value为方法处理器
private final Map dispatch;
...
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
//创建一个HystrixCommand命令,对同步方法调用器进行封装
HystrixCommand