历史文章(文章累计440+)
服务信息上报+记录请求信息+监听项目运行状态还能这么玩「扩展点系列」- 第440篇
配置类信息赋值为Java静态变量「扩展点实战系列》」- 第441篇
3种方案扩展RestTemplate让其具备负载均衡(超级详细)「扩展点实战系列」- 第442篇
一个注解@LoadBalanced就能让RestTemplate拥有负载均衡的能力?「扩展点实战系列」- 第443篇
Spring注解@Qualifier的详细用法你知道几种「扩展点实战系列」- 第444篇
利用Spring扩展点模拟Feign实现远程调用(干货满满)「扩展点实战系列」- 第445篇
师傅:徒儿,你今天充电了吗?
悟纤:充电?天啦噜,师傅我又不是新能源汽车,充电干吗?
师傅:你out了,此充电非彼充电?
悟纤:师傅,你是要说,我学习充电了吗?
师傅:徒儿,不赖耶,有这么意思。这里的“充电“有很多含义。
悟纤:愿闻其详。
师傅:你今天充电了吗?可以理解为你今天学习了吗?给你的大脑充电。
悟纤:还有呐?
师傅:你今天充电了吗?可以理解为你今天锻炼了吗?给你的身体充电。
悟纤:师傅,还有吗?
师傅:你今天充电了吗?可以理解为你今天冥想/瑜伽等活动?给你的心灵充电。
师傅:总的来说,你今天充电了吗?也就是说你今天学习了吗?锻炼身体了吗?放空自我了吗,不同场景不同理解吧~
悟纤:师傅这句话好,我要时刻问我自己,今天充电了吗?提醒我时刻要学习要成长。
师傅:那咱们开始来学习吧。
悟纤:\(^o^)/ 欧耶,来也~
导读
在前面的小节,我们简单的模拟了一下FeignClient的实现方式,对于FeignClient具体又是怎么实现的呢?实现的核心点是否也是使用了Spring的扩展点呢?
带着这些疑问,我们深入到FeignClient的源码一探究竟。
👇🏻👇🏻👇🏻扩展点实战系列:
01.《观察者模式实际应用场景「扩展点实战系列」》
02.《服务信息上报+记录请求信息+监听项目运行状态还能这么玩🐴「扩展点实战系列」》
03.《配置类信息赋值为Java静态变量「扩展点实战系列》」》
04. 《3种方案扩展RestTemplate让其具备负载均衡(超级详细)「扩展点实战系列」》
05.《一个注解@LoadBalanced就能让RestTemplate拥有负载均衡的能力?「扩展点实战系列」》
06.《Spring注解@Qualifier的详细用法你知道几种「扩展点实战系列」》
07.《利用Spring扩展点模拟FeignClient实现远程调用(干货满满)「扩展点实战系列」》
08.《深入FeignClient源码吃透Spring扩展点「扩展点实战系列」》
09.「待拟定」
一、FeignClient的使用
首先我们先看下FeignClient的使用。
1.1 启用Feign
首先启用Feign指定要扫描的包路径,也可以不指定,使用默认的启动路径:
核心代码是:@EnableFeignClients
1.2 使用Feign
看下Feign如何使用的:
说明:
(1)@RequestLine是Feign默认提供的契约注解。
(2)@RequestMapping这是集成了Spring MVC的注解。这个和我们自己实现的@FeignMethod使用起来很像。
1.3 调用OrderInfoFeignService
在Controller中调用:
到这里使用的层面,和前面的小节我们自己模拟的FeignClient还是很相似的,那么底层的实现源码是否是一样的呐?接着往下看。
二、FeignClient源码分析
接下来深入源码看看具体的FeignClient一些实现。这里我们只关注和Spring扩展点相关的,毕竟这一系列的主角是Spring扩展点,而并非是Feign。
2.1 EnableFeignClients
先看下入口注解类EnableFeignClients:
说明:
(1)属性basePackages允许指定扫描的包路径。
(2)@Import:使用@Import导入的方式实现把实例FeignClientsRegistrar加入到Spring的IOC容器中。
至于FeignClientsRegistrar做了什么,往下看~
2.2 FeignClientsRegistrar
进入到类FeignClientsRegistrar看下:
该类最重要的就是实现了接口ImportBeanDefinitionRegistrar,那么就要实现相应的方法registerBeanDefinitions,找到该方法看下:
这里有两个方法,通过方法名称可以看出一个注册默认的配置信息,一个是注册FeignClients,我们能看出核心的应该是第二个方法。
这里也顺带看下第一个方法做了什么?
主要是处理EnableFeignClients注解上的信息。
看下第二个方法registerFeignClients():
说明:通过ClassPathScanningCandidateComponentProvider扫描@EnableFeignClients设置的包路径下配置了注解@FeignClient的接口信息。
然后进行注册,这里还没有看到具体的注册代码,而是又调用了一个方法registerFeignClient():
使用了BeanDefinitionBuilder添加各种属性,从而构造BeanDefinition,具体注册那一行关键代码,需要进入到方法
BeanDefinitionReaderUtils.registerBeanDefinition:
2.3 FeignClientFactoryBean
啊哈,怎么没看到为Bean定义设置bean class呢?细看之前截图的一段代码:
在这里指定了BeanClass,接下里来看下FeignClientFactoryBean的关键代码:
是不是看到了实现了接口FactoryBean,是不是我们实现的思路是一样的,看下getObject方法:
这里一丢代码,核心的就是最后targeter.target()这个方法,调用Targeter的target方法会使用动态代理生成@FeignClient接口的代理对象:
是不是这里代码都看懵了,不重要,你只需要能看到InvocationHandlerFactory就可以:
InvocationHandler就很熟悉了吧,JDK的动态代理方法增强处理器。
总结
从增加@EnableFeignClients注解开始,当我们启动应用的时候,系统就会扫描所有的包里面带有@FeignClient接口的类,并为此生成代理对象,这个代理对象会设置我们写的各种配置与拦截器,并最终注入到Spring的IOC容器中,当我们调用@FeignClient接口的类的方法时,其实是调用生成的代理类的方法。