引言
上文我们讲述了整个Open-Feign的使用和大的思想,我们知道了整体是基于JDK的动态代理来实现的,而JDK动态代理的核心又是InvocationHandler,所以本章我们就从InvocationHandler入口来探索整个Open-Feign是如何实现远程调用的。
揭露Open-Feign的入口
当JDK动态代理对象调用方法时,会执行InvocationHandler的invoke方法,因此我们先要关注Open-Feign中构建动态代理的InvocationHandler具体实现,看源码会发现有两个实现:一个是FeignInvocationHandler,另一个是FeignCircuitBreakerInvocationHandler,两者的区别在于:
- 所属:FeignInvocationHandler是属于原生Feign的,而FeignCircuitBreakerInvocationHandler是Open-Feign新增的
- 功能:两者都能完成RPC的调用,FeignCircuitBreakerInvocationHandler是在FeignInvocationHandler的基础上封装了一层熔断降级的处理,即集成了CircuitBreaker的功能
可以说FeignCircuitBreakerInvocationHandler是FeignInvocationHandler的增强版,但整个RPC请求的核心功能都是一样的,本章我们基于FeignInvocationHandler来进行研究这一过程,如下:
探索Open-Feign的处理核心
在上图中,我们发现当请求调用FeignInvocationHandler的invoke方法后会调用到SynchronousMethodHandler的invoke方法,所以整个核心的处理逻辑就在此处了。
在查看Open-Feign的具体处理逻辑之前,我们可以自己先来想一想:我们要实现RPC调用,那么我们需要将我们要请求的信息封装成一个Http请求报文,然后通过Http客户端发起Http请求,然后接收响应进行处理;Open-Feign的处理逻辑也是这样,但是为了更好了理解Open-Feign的处理流程,我们熟悉下其中的一些概念:
1、相关概念
- Contract:用来解析标记@FeignClient接口中的所有与方法,输出MethodMetadata
- MethodMetadata:对应方法的元信息,是对执行方法的解析获取到的请求url和请求参数相关信息的封装,由Contract#parseAndValidateMetadata解析获取到
- RequestTemplate.Factory:会根据传入的请求参数args以及方法的元信息MethodMetadata转换成RequestTemplate
- RequestTemplate:是构建Http的Request的一个模板,其中包含了url,header,HttpMethod,body等相关信息
- Target:主要用于将RequestTemplate转换为Feign的feign.Request
- feign.Request:这是Feign对外的Http请求封装
- feign.Response:这是Feign对外的Http响应封装
- Client:Feign中定义对外的Http请求客户端规范:feign.Client,真正的Http客户端会以代理对象的形式组合到feign.Client的实现中
- Retryer:重试器,当Http请求执行失败且抛出可重试异常时重试器会进行重试
- RequestInterceptor:请求的拦截器,可以对RequestTemplate进行调整
- Encoder:请求的编码器
- Decoder:响应的解码器
2、核心处理流程
其实,当我们梳理清楚了上面的几个概念后,再来查看整个链路就很清晰了,Open-Feign实现RPC的整个执行逻辑如下图:
- 首先在构建动态代理的时候会通过Contract组件来帮我们构建出MethodMetadata
- 当请求来的时候RequestTemplate.Factory会通过请求参数args,MethodMetadata以及编码器Encoder来构建出RequestTemplate
- Target组件会将RequestTemplate转换成feign.Request,然后丢给Client进行Http请求
- 请求成功会返回feign.Response,并使用解码器对Response进行解码,返回想要的输出,从而完成一次请求
NOTE:其中,整个过程中如果发生可重试的异常且在重试的次数内就会发起请求重试
总结
这两篇文章,笔者主要聊了聊Open-Feign的使用和实现的思想和逻辑,并没有花太多的时间在源码上。因为笔者认为,思想相对于实现而言,思想更重要,实现可以有各种各样,但思想才是王道,它是你实现的宗旨,掌握了思想再去看那些实现会轻松很多,也会学到更多,希望与大家共勉!
另外,关于Open-Feign的熔断降级,负载均衡,以及具体HttpCllient的可插拔配置等等高级使用,我们后续慢慢来聊。