OpenFeign源码3-2020.0.X版本开始的OpenFeign底层不再使用Ribbon
欢迎大家关注 github.com/hsfxuebao ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈
0. 环境
- nacos版本:1.4.1
- Spring Cloud : Hoxton.SR9(
没用2020.0.2版本后面说明
) - Spring Boot :2.4.4
- Spring Cloud alibaba: 2.2.5.RELEASE
- Spring Cloud openFeign 2.2.2.RELEASE
2020.0.X版本
开始的OpenFeign底层不再使用Ribbon了
本文基于OpenFeign高版本(SpringCloud 2020.0.x版本开始之后的版本)讨论:OpenFeign新版本和旧版本之间的差异(高版本OpenFeign底层不使用Ribbon做负载均衡)
PS:本文使用的SpringCloud高版本:
<properties>
<spring-boot.version>2.4.4</spring-boot.version>
<spring-cloud.version>2020.0.2</spring-cloud.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
</properties>
PS:本文使用的SpringCloud低版本:
<properties>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>
</properties>
1. 源码主流程版本间差异串讲
1.1 @FeignClientsRegistrar开启对FeignClient的扫描
此处主流程上无区别;
在SpringBoot启动流程中@FeignClientsRegistrar
注解开启OpenFeign的入口、OpenFeign扫描所有的FeignClient的流程 高版本和低版本基本一样,低版本的见文章:OpenFeign源码2-Bean注册过程和调用过程
主要流程如下:
开启扫描FeignClient的入口: 启动类上添加的
@EnableFeignClients
注解会通过@Import
注解在SpringBoot启动流程中将ImportBeanDefinitionRegistrar
接口的实现类FeignClientsRegistrar
注入到启动类的ConfigurationClass
的属性中,在注册启动类的BeanDefinition
时,会遍历调用其@Import
的所有ImportBeanDefinitionRegistrar
接口的registerBeanDefinitions()
方法。扫描
FeignClient
: 拿到@EnableFeignClients
注解中配置的扫描包路径相关的属性,得到要扫描的包路径; 获取到扫描器ClassPathScanningCandidateComponentProvider
,然后给其添加一个注解过滤器(AnnotationTypeFilter)
,只过滤出包含@FeignClient
注解的BeanDefinition
; 扫描器的findCandidateComponents(basePackage)
方法从包路径下扫描出所有标注了@FeignClient
注解并符合条件装配的接口;然后将其在BeanDefinitionRegistry
中注册一下;
1.2 为FeignClient生成动态代理类
区别主要体现在这里;
在注册FeignClient
到Spring容器时,构建的BeanDefinition
的beanClas是FeignClientFactoryBean
;FeignClientFactoryBean
是一个工厂,保存了@FeignClient
注解的所有属性值,在Spring容器初始化的过程中,其会根据之前扫描出的FeignClient
信息构建FeignClient
的动态代理类。详见OpenFeign源码2-Bean注册过程和调用过程
底层通信Client的区别?
在使用Feign.Builder
构建FeignClient
的时候,获取到的Client是FeignBlockingLoadBalancerClient
(这其中的逻辑后面聊,在OpenFeign低版本是LoadBalancerFeignClient
);用于生成FeignClient
的Targeter
是DefaultTargeter
(在OpenFeign低版本是HystrixTargeter,高版本移除了Hystrix,采用Spring Cloud Circuit Breaker
做限流熔断);
具体体现在FeignClientFactoryBean#loadBalance()
方法,其是一个进行负载均衡的FeignClient
动态代理生成方法;
OpenFeign低版本:
FeignBlockingLoadBalancerClient何时注入到Spring容器?
FeignBlockingLoadBalancerClient
注入到Spring
容器的方式和OpenFeign
低版本的LoadBalancerFeignClient
是一样的;
进入到FeignBlockingLoadBalancerClient
类中,看哪里调用了它唯一一个构造函数;
找到FeignBlockingLoadBalancerClient
发现有三个地方调用了它的构造函数,new了一个实例;
- DefaultFeignLoadBalancedConfiguration
- HttpClientFeignLoadBalancedConfiguration
- HttpClient5FeignLoadBalancerConfiguration
- OkHttpFeignLoadBalancedConfiguration
再结合默认的配置,只有DefaultFeignLoadBalancedConfiguration
中的Client符合条件装配;
可以通过引入Apache HttpClient
的maven依赖使用HttpClientFeignLoadBalancedConfiguration
,
或引入OkHttpClient
的maven依赖并在application.yml
文件中指定feign.okhttp.enabled
属性为true
使用OkHttpFeignLoadBalancedConfiguration
。
DefaultTargeter在哪里注入到Spring容器?
DefaultTargeter
注入到Spring容器的方式和OpenFeign低版本的HystrixTargeter
是一样的;
在FeignAutoConfiguration
类中可以找到Targeter
注入到Spring容器的逻辑;
后续生成动态代理类的逻辑和旧版本一样
都体现在ReflectiveFeign#newInstance()
方法中:
2. Client处理负载均衡(核心区别)
上面提到OpenFeign
高版本获取到的Client
是FeignBlockingLoadBalancerClient
,而低版本的是LoadBalancerFeignClient
,LoadBalancerFeignClient
基于Ribbon实现负载均衡
,FeignBlockingLoadBalancerClient
就靠OpenFeign自己实现负载均衡
;
接下来浅看一下FeignBlockingLoadBalancerClient
是如何做负载均衡的!!
2.1 FeignBlockingLoadBalancerClient选择一个服务实例
参考文章
spring-cloud-openfeign-2.2.2源码分析 springcloud-source-study学习github地址 图说系列:OpenFeign源码解析 Spring Cloud 源码分析之OpenFeign Spring Cloud openFeign学习【3.0.2版本】 微服务入门到入土
转载自:https://juejin.cn/post/7168654876757458974