感觉这一年来学习的知识点都是零零碎碎的,没有形成一个系统闭环,于是萌生了系统总结 Spring Cloud 源码相关的知识点的想法。后续会持续更新系统性的文章。纯原创,debug 总结。今天先简单debug下 OpenFegin 的创建吧。
项目结构
标准的 SpringCloud 项目。
- authservice:认证服务。Oauth2 那套认证逻辑
- common:公共模块
- gateway:网关模块
- xxy-service-api:所有接口都写在这
- xxy-service:所有接口实现类在这
user-api 定义了一个 getUser 接口
具体的 getUser 接口的实现是在认证服务里面(authservice)
利用 OpenFegin 可以很轻松的实现,不同服务间接口的互相调用。接下来去看源码。
分析 @FeignClient 注解
直接点击进入 FeignClient 所在的源码包里面分析,如下图,然后大概看到一个名字为 FeignClientFactoryBean 的类,毫不犹豫的点进去看 FeignClientFactoryBean 就行
可以看到 FeignClientFactoryBean 还实现了Spring 提供的一些扩展方法: InitializingBean( populateBean 属性填充完成后,进行初始化 Bean)、ApplicationContextAware(用来获取Spring 上下文对象)、BeanFactoryAware。主要还是看和 FeignClientFactoryBean相关的就行。直接把 getObject 方法点到底就行。下面贴我 debug 的时序流程图,沿着圈红的方法点,嵌套这么多方法.
ok 点到底我们发现我们用到的Fegin 其实就是一个Jdk代理对象,里面织入了一个 InvocationHandler 的增强逻辑。每次我们调用Fegin 接口前,都会先掉 InvocationHandler 增强逻辑。到此 Fegin 的创建源码就结束了。
InvocationHandler handler = this.factory.create(target, methodToHandler);
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
Iterator var12 = defaultMethodHandlers.iterator();
小结OpenFegin创建流程
通过Spring 的 SPI功能扫描,将定义好的Fegin接口生成BeanDefinition(估计也是替换BeanClass为FactoryBean),然后利用 FactoryBean批量进行创建,然后通过Jdk动态代理,将增强逻辑织入到我们的Fegin代理对象中。具体细节没有进行细看,因为debug的过程中看到工厂Bean我就大概知道创建流程了。和我之前手写过的Mybatis动态生成Mapper的思想差不多。
手写 Mybatis-plus 基础架构(工厂模式+ Jdk 动态代理统一生成代理 Mapper)
OpenFegin参数组装源码
入口AbstractLoadBalancerAwareClient类下面的executeWithLoadBalancer方法。限于篇幅,中间的过程就不一一贴出来了,直接展示关键节点。
通过debug我们发现,当发起 http://localhost:9002/xxy-course/getUser 的请求后,最终经过lb负载均衡,会将请求转换成我们的真实请求地址http://192.168.11.101:8111/getUser
如何组装url的,源码位于LoadBalancerContext类下面的reconstructURIWithServer方法,没啥好看的,就是参数拼接。
OpenFegin发送请求源码
通过debug,可以看到最终是调用FeignLoadBalancer下面的execute方法去发起的网络请求。
中间过程有点多,直接贴debug时序图
最终来到fegin.Client类下面的convertAndSend方法里面。通过抽丝剥茧可以看到fegin是通过HttpURLConnection进行的发起网络请求,而不是我先前以为Fegin其实就是Httpclient的包装。小丑竟然是我自己
到此fegin的整个调用以及创建链路源码全部看完,其中的负载均衡、解码器部分的源码后续更新。