SpringCloud OpenFeign原来是这么基于Ribbon来实现负载均衡的二

发布于 2022-6-16 17:50
浏览
0收藏

 

首先调用了targetRequest方法,贴出源码

Request targetRequest(RequestTemplate template) {
    for (RequestInterceptor interceptor : requestInterceptors) {
      interceptor.apply(template);
    }
    return target.apply(template);
  }

 

这个方法会遍历所有的拦截器RequestInterceptor,这是feign的一个扩展点,也就说再发送请求前,你仍然还有机会对请求的内容进行调整,比如说加个请求头,这也是很常见的一种方式,在微服务之间鉴权的时候使用。RequestInterceptor是在构建Feign.Builder的时候传进来的,Feign.Builder的组件都是通过ioc容器获取的,组件又是通过配置类来的,所以你需要的话就可以在配置类中声明RequestInterceptor对象。配置类有不同的优先级,按照自己的需求,可以在其中一个优先级使用,不过一般这种通用的东西,不是某个微服务特有的功能,一般选择在springboot启动中的容器中配置。

 

执行完targetRequest,回到executeAndDecode之后,会构建出一个Request,Request很好理解,就是一个请求,里面封装了http请求的东西。接下来就会调用Client的execute方法来执行请求,拿到响应,接下来就是基于处理这个响应,将响应数据封装成需要返回的参数,之后返回给调用方。

 

到这里,我们已经分析出接口的动态代理是如何运行的。其实就是通过每个方法对应的MethodHandler来实现的,MethodHandler主要就是拼接各种参数,组装成一个请求,随后交由Client接口的实现去发送请求。

 

二、LoadBalancerFeignClient


 通过上面分析整个动态代理调用过程可以看出,Client是发送http请求的关键类。那么Client是什么玩意?还记得我在关于OpenFeign动态代理生成的那篇文章中留下的一个疑问么,当Feign客户端在构建动态代理的时候,填充很多组件到Feign.Builder中,其中有个组件就是Client的实现,我们并没有在FeignClientsConfiguration配置类中找到关于Client的对象的声明。不过当时我就提到了,这个组件的实现是要依赖负载均衡的,也就是这个组件是Feign用来整合Ribbon的入口。

 

接下来,我们就着重看一下Client的实现,看看Feign是如何通过ribbon实现负载均衡的。

 

我们先来看一下Feign跟ribbon整合的配置类。

@Import({ HttpClientFeignLoadBalancedConfiguration.class,
    OkHttpFeignLoadBalancedConfiguration.class,
    DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {

  @Bean
  @Primary
  @ConditionalOnMissingBean
  @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
  public CachingSpringLoadBalancerFactory cachingLBClientFactory(
      SpringClientFactory factory) {
    return new CachingSpringLoadBalancerFactory(factory);
  }

  @Bean
  @Primary
  @ConditionalOnMissingBean
  @ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
  public CachingSpringLoadBalancerFactory retryabeCachingLBClientFactory(
      SpringClientFactory factory, LoadBalancedRetryFactory retryFactory) {
    return new CachingSpringLoadBalancerFactory(factory, retryFactory);
  }

  @Bean
  @ConditionalOnMissingBean
  public Request.Options feignRequestOptions() {
    return LoadBalancerFeignClient.DEFAULT_OPTIONS;
  }

}

我们来分析一下,首先通过@Impot注解导入了三个配置类。

  • HttpClientFeignLoadBalancedConfiguration:基于HttpClient实现http调用的。
  • OkHttpFeignLoadBalancedConfiguration:基于OkHttp实现http调用的。
  • DefaultFeignLoadBalancedConfiguration:默认的,也就是Feign原生的发送http的实现。

 

这里我们看一下DefaultFeignLoadBalancedConfiguration配置类,因为默认就是这,HttpClientFeignLoadBalancedConfiguration和OkHttpFeignLoadBalancedConfiguration都需要有引入HttpClient和OkHttp依赖才会有用

@Configuration(proxyBeanMethods = false)
class DefaultFeignLoadBalancedConfiguration {

  @Bean
  @ConditionalOnMissingBean
  public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
      SpringClientFactory clientFactory) {
    return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory,
        clientFactory);
  }

}

 

这个配置类很简单,声明了LoadBalancerFeignClient到spring容器,传入了三个参数,一个Client的实现,一个CachingSpringLoadBalancerFactory和一个SpringClientFactory。LoadBalancerFeignClient这个类实现了Client接口,也就数说我们在构建Feign.Builder填充的就是这个对象,也就是上面说feign的执行流程最后用来执行请求的Client的实现。

 

接下来我说一下入参的三个参数是什么意思。

  • Client.Default:就是Feign自己实现的Client,里面封装了真正发送http发送请求的功能,LoadBalancerFeignClient虽然也实现了Client接口,但是这个实现其实是为了整合Ribbon用的,并没有发送http的功能,所以需要有个可以发送http功能的实现。
  • CachingSpringLoadBalancerFactory:后面会说这个类的作用
  • SpringClientFactory:这个跟Feign里面的FeignContext的作用差不多,用来实现配置隔离的,当然,这个也在关于Ribbon的那篇文章有剖析过。

 
其实大家可以自行去看OkHttpFeignLoadBalancedConfiguration和HttpClientFeignLoadBalancedConfiguration,其实他们配置跟DefaultFeignLoadBalancedConfiguration是一样的,声明的对象都是LoadBalancerFeignClient,只不过将Client.Default换成了基于HttpClient和OkHttp的实现,也就是发送http请求使用的工具不一样。

 

FeignRibbonClientAutoConfiguration除了导入配置类还声明了CachingSpringLoadBalancerFactory,只不过一种是带基于spring实现的重试功能的,一种是不带的,主要看有没有引入spring重试功能的包,所以上面构建LoadBalancerFeignClient注入的CachingSpringLoadBalancerFactory就是在这声明的。

 

文章转自公众号:三友的java日记

已于2022-6-16 17:50:20修改
收藏
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐