深入Feign源码吃透Spring扩展点「扩展点实战系列」- 第446篇

发布于:2022-11-28 ⋅ 阅读:(312) ⋅ 点赞:(0)

历史文章(文章累计440+)

国内最全的Spring Boot系列之一

国内最全的Spring Boot系列之二

国内最全的Spring Boot系列之三

国内最全的Spring Boot系列之四

国内最全的Spring Boot系列之

服务信息上报+记录请求信息+监听项目运行状态还能这么玩「扩展点系列」- 第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接口的类的方法时,其实是调用生成的代理类的方法

本文含有隐藏内容,请 开通VIP 后查看