SpringCloud系列之Feign-8.深入了解FeignContract协议解析过程

SpringCloud系列之Feign-8.深入了解FeignContract协议解析过程,第1张

首先看Contract这个接口类中只有一个parseAndValidatateMetadata方法,其余两个都是子类,我们可以打个断点逐步跟一下。

其中BaseContract这个类主要是做数据验证的功能

断点进来之后我们可以看到,实例中是一个IService的类,然后下面有两个checkState方法,checkState方法是做个验证,如果第一个参数true则走过,如果是false则返回异常信息。

其中targetTypegetTypeParameters()是获取类的泛型,在Feign中是不允许有泛型的,如果有则返回Parameterized types unsupported class name的异常

第二个targetTypegetInterfaces()length <= 1的意思就是这个类只能做单继承,否则继续抛出异常。

这个验证如果没问题就尽心下一个验证了:

如果这个类继承了一个类,那么我们就看下继承的类是否又继承了类,如果又继承了,则抛出错误: 该类仅支持单层次的继承。

这个方法就是判断类不能是个对象,也不能有static方法,下面还有个UtilisDefault(method)方法:

这里是判断方法不能仅仅是个pulic方法,且必须是个接口才行,看不懂的可以参见帖子:

>

大数据(big data),指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。大数据的5V特点(IBM提出):Volume(大量)、Velocity(高速)、Variety(多样)、Value(低价值密度)、Veracity(真实性),平台有hadoop

Feign是一个声明式的web服务客户端,它使得web服务调用非常的简单,当我们使用Feign时,Spring Cloud

整合了Ribbon和Eureka,从而为我们提供了一个负载均衡的>

@EnableFeignClients 源码比较值得一读,读完之后我们就学会了如何自己写一个注解并成功运用起来了

1首先我们进入到 @EnableFeignClients注解里面可以看到这个注解里面声明了几个属性,通过名称大概可以看到比如basePackages应该是包路径,value的话应该是个basePackages别名,我们暂且不管,看下这个注解上面有个@Import的注解,点进去这个类来看一下

2如图可以看到FeignClientsRegistrar这个类实现了三个Spring的类,根据名称大概猜一下,第一个应该是关于类定义注册的类,第二个第三个相信大家可能用过或者了解过就是Spring的Aware的一些类,大致就是加载资源或者环境变量的类

那我们看一下ImportBeanDefinitionRegistrar类里面是什么:

可以看到里面定义了一个方法,那么我们重新返回到FeignClientsRegistrar看下他是怎么实现这个方法的:

这个方法主要干了两件事儿,第一个方法是注册了默认的配置信息,第二个就是注册FeignClients,我们挨个一个个详细的看下:

到了较为详细的源码时候,如果看不懂,我们最好是打断点,当我们启动了Eureka-server,Eureka-client,然后再启动Feign-consumer的时候,断点就可以进来,我们可以看到一些传参的信息:

可以看到这个metedata里面的数据刚好就是在启动类上面的三个注解,并且还带有三个注解的属性信息,下面再给大家看下主类对照下就懂了:

然后我们继续往下面学习:

这一步就比较好理解了,我们拿到EnableFeignClients这个注解的属性信息。

然后就是拼接了一个名称,这个名称就是启动类的前端加了个default而已,然后registry没变还是传参过来,defaultAttrsget("defaultConfiguration")这个属性从刚刚断点来看也是空的。调用了一个registerClientConfiguration方法:

这个方法就是使用了Spring的BeanDefinitionBuilder把FeignClientSpecification这个bean给注册到Spring容器中了。

然后我们继续放回到主方法中看下一个方法:

这个方法根据名称registerFeignClients来说应该就是注册FeignClients类了,进入方法中,第一个scanner我们看下:

有点看不懂,没关系,猜一下,可能是扫描类的工具把。

我们继续王下面走,scanner加载了一个resourceLoader这个类,这个类我们可以查一下,他是Spring框架中与资源相关的类,然后再往下看

下面还是获取主类中的注解EnableFeignClients的属性信息

再往下,我们可以从图中看到在属性中获取关于clients的信息,但是没有,然后scanner就加了一个类似过滤器的东东,然后调用了getBasePackages的方法

下面我们看下getBasePackages方法:

看过之前的方法,这个方法就好理解了,首先就还是获取EnableFeignClients的所有属性信息,然后把值都给取出来,取得属性分别是value还是basePackages等关于包路径的属性值,如果都没有获取到,就获取一个默认的包路径

这个包路径断点可以看到就是主类的包路径,所以整体上看,这些逻辑就是首先看注解中有没有关于FeignClient的包路径信息,如果没有配置,那程序就准备从主程序所在的包路径下找所有的FeignClient了。

我们再详细看下:

然后继续看这个registerClientConfiguration方法:

这个方法我们之前看过就是把某个类加载到Spring中所以继续下一步,看registerFeignClient方法:

获取到这个FeignClient的所有属性之后,我们就进行数据处理,把属性信息都赋值给definition

这个方法表示我们把这个类以 按照类型注入 作为属性,然后

这块逻辑就是为了防止两个有同一个父类的FeignClient出现问题所做的,我们应该都遇到过一个问题就是 使用 @Autowire注入类的时候发现报错,说是有两个类不知道注入哪一个,而如果其中一个有@primary注解的话,spring是会优先注入这个类的。

下面就没什么了,直到最后执行了

整个@EnableFeignClients的实现到此执行完毕,这个注解的源码相对来说看起来算是比较清晰明了了,而且对于我们如果有做一个新注解的需求的话,完全可以参照着做,非常具有模板意义。

关于Feign的启动原理分析,参照另一篇 Spring Cloud Feign 源码分析 - feign启动原理

书接上文,上篇最后提到所有带@FeignClient注解的interface都被封装成FeignClientFactoryBean的BeanDefinition。从名字上可以得知这个类是一个FactoryBean。关于FactoryBean的介绍参考

因此直接找getObject()。

getTarget方法首先获取FeignContext的对象,基于这个context对当前feign的配置信息存放到Builder中。

首先实例化bean:FeignContext

FeignContext的定义在FeignAutoConfiguration

第一次除了创建新的FeignContext对象之外,还设置了一组configurations,

这组configurations是FeignClientSpecification类型,通过autowired注入。

在扫描EnableFeignClients和各个FeignClient时,将configuration对应的class封装成了FeignClientSpecification的BeanDefinition,这里从容器中取出来创建对象注入到configurations

通过断点可以看到这里有15个FeignClientSpecification的对象

一个是default开头的在启动类里配置的configuration,剩下的都是FeignClient的configuration。

FeignContext继承了NamedContextFactory,对应的范型就是FeignClientSpecification,看下NamedContextFactory构造方法

这里设置了默认的defaultConfigType,feign里用的是FeignClientsConfiguration,定义了一系列的默认值。

在获取到FeignContext之后,开始封装FeignBuilder。

首先通过context实例化FeignLoggerFactory的对象,因为context是NamedContextFactory的子类,会给每个contextId创建一个独立的AnnotationConfigApplicationContext上下文,每一个k-v会存储在FeignContext的全局context中,key就是contextId

这三个方法的实现完全体现了NamedContextFactory的作用:

给每个name创建一个单独的ApplicationContext子上下文对象,后续凡是这个name的ioc *** 作,都由独立的ApplicationContext来完成,name之间的context相互隔离。所有的子上下文保存在了Map<String, AnnotationConfigApplicationContext> contexts中。

在创建Context时,补充了configuration的设置:

首先(1的位置),从全局的configurations查找是否定义了只对当前name生效的configuration,也就是判断在当前name所属的FeignClient注解上是否定义了configuration。如果定义过,将这个configuration的Class封装成BeanDefinition注册到本name的子上下文中。

接着(2的位置),从全局的configurations查找是否定义了全局配置,也就是@EnableFeignClients的defaultConfiguration的值,这里固定前缀是default。

如果也存在,就也将这个defaultConfiguration的Class封装成BeanDefinition注册到本name的子上下文中。

第一次调用完毕get方法后,给每个FeignClient创建的FeignContext就完成了configuration初始化的动作,后面的所有 *** 作,如配置encoder、decoder都是给当前的子上下文内注册BeanDefinition。最后将所有配置封装成Builder返回。

在getTarget()构造完成builder属性之后,开始了整个请求调度过程。

先看第一段:

如果没有url属性,就用name来处理,把>

以上就是关于SpringCloud系列之Feign-8.深入了解FeignContract协议解析过程全部的内容,包括:SpringCloud系列之Feign-8.深入了解FeignContract协议解析过程、(三)OpenFeign、Feign 请求其它服务无法获取数据等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9693838.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存