首先看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 请求其它服务无法获取数据等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)