feign直接走熔断_Java后端精选技术:深入理解Feign

什么是Feign

Feign是由Retrofit,JAXRS-2.0和WebSocket启发的一个java到http客户端绑定。 Feign的主要目标是将Java Http Clients变得简单。Feign的源码地址:https://github.com/OpenFeign/feign

写一个Feign

在我之前的博文有写到如何用Feign去消费服务,简单的实现一个Feign客户端,首先通过@FeignClient,客户端,其中value为调用其他服务的名称,FeignConfig.class为FeignClient的配置文件,代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第1张图片

其配置文件如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第2张图片

查看FeignClient的源码,其代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第3张图片

feign 用于声明具有该接口的REST客户端的接口的注释应该是创建(例如用于自动连接到另一个组件。 如果功能区可用,那将是 用于负载平衡后端请求,并且可以配置负载平衡器 使用与伪装客户端相同名称(即值)@RibbonClient 。

其中value()和name()一样,是被调用的 service的名称。 url(),直接填写硬编码的url,decode404()即404是否被解码,还是抛异常;configuration(),标明FeignClient的配置类,默认的配置类为FeignClientsConfiguration类,可以覆盖Decoder、Encoder和Contract等信息,进行自定义配置。fallback(),填写熔断器的信息类。

FeignClient的配置

默认的配置类为FeignClientsConfiguration,这个类在spring-cloud-netflix-core的jar包下,打开这个类,可以发现它是一个配置类,注入了很多的相关配置的bean,包括feignRetryer、FeignLoggerFactory、FormattingConversionService等,其中还包括了Decoder、Encoder、Contract,如果这三个bean在没有注入的情况下,会自动注入默认的配置。

  • Decoder feignDecoder: ResponseEntityDecoder(这是对SpringDecoder的封装)
  • Encoder feignEncoder: SpringEncoder
  • Logger feignLogger: Slf4jLogger
  • Contract feignContract: SpringMvcContract
  • Feign.Builder feignBuilder: HystrixFeign.Builder

代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第4张图片

重写配置:

你可以重写FeignClientsConfiguration中的bean,从而达到自定义配置的目的,比如FeignClientsConfiguration的默认重试次数为Retryer.NEVER_RETRY,即不重试,那么希望做到重写,代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第5张图片

在上述代码更改了该FeignClient的重试次数,重试间隔为100ms,最大重试时间为1s,重试次数为5次。

Feign的工作原理

feign是一个伪客户端,即它不做任何的请求处理。Feign通过处理注解生成request,从而实现简化HTTP API开发的目的,即开发人员可以使用注解的方式定制request api模板,在发送http request请求之前,feign通过处理注解的方式替换掉request模板中的参数,这种实现方式显得更为直接、可理解。

通过包扫描注入FeignClient的bean,该源码在FeignClientsRegistrar类: 首先在启动配置上检查是否有@EnableFeignClients注解,如果有该注解,则开启包扫描,扫描被@FeignClient注解接口。代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第6张图片

扫描到FeignClient后,将信息取出,以bean的形式注入到ioc容器中,源码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第7张图片
feign直接走熔断_Java后端精选技术:深入理解Feign_第8张图片

注入bean之后,通过jdk的代理,当请求Feign Client的方法时会被拦截,代码在ReflectiveFeign类,代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第9张图片

在SynchronousMethodHandler类进行拦截处理,当被拦截会根据参数生成RequestTemplate对象,该对象就是http请求的模板,代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第10张图片

其中有个executeAndDecode()方法,该方法是通RequestTemplate生成Request请求对象,然后根据用client获取response。

feign直接走熔断_Java后端精选技术:深入理解Feign_第11张图片

Client组件

其中Client组件是一个非常重要的组件,Feign最终发送request请求以及接收response响应,都是由Client组件完成的,其中Client的实现类,只要有Client.Default,该类由HttpURLConnnection实现网络请求,另外还支持HttpClient、Okhttp.

首先来看以下在FeignRibbonClient的自动配置类,FeignRibbonClientAutoConfiguration ,主要在工程启动的时候注入一些bean,其代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第12张图片

在缺失配置feignClient的情况下,会自动注入new Client.Default(),跟踪Client.Default()源码,它使用的网络请求框架为HttpURLConnection,代码如下:

3f8a140128b0ea15940b33e204a86189.png

怎么在feign中使用HttpClient,查看FeignRibbonClientAutoConfiguration的源码

feign直接走熔断_Java后端精选技术:深入理解Feign_第13张图片

从代码@ConditionalOnClass(ApacheHttpClient.class)注解可知道,只需要在pom文件加上HttpClient的classpath就行了,另外需要在配置文件上加上feign.httpclient.enabled为true,从 @ConditionalOnProperty注解可知,这个可以不写,在默认的情况下就为true.

在pom文件加上:

93f80018a458e14c6fc851480a6ab849.png

同理,如果想要feign使用Okhttp,则只需要在pom文件上加上feign-okhttp的依赖:

bc3a00654ad46694d6f60b7e7ee88e2c.png

feign的负载均衡是怎么样实现的呢?

通过上述的FeignRibbonClientAutoConfiguration类配置Client的类型(httpurlconnection,okhttp和httpclient)时候,可知最终向容器注入的是LoadBalancerFeignClient,即负载均衡客户端。现在来看下LoadBalancerFeignClient的代码:

feign直接走熔断_Java后端精选技术:深入理解Feign_第14张图片

其中有个executeWithLoadBalancer()方法,即通过负载均衡的方式请求。

feign直接走熔断_Java后端精选技术:深入理解Feign_第15张图片

其中服务在submit()方法上,点击submit进入具体的方法,这个方法是LoadBalancerCommand的方法:

feign直接走熔断_Java后端精选技术:深入理解Feign_第16张图片

上述代码中有个selectServe(),该方法是选择服务的进行负载均衡的方法,代码如下:

feign直接走熔断_Java后端精选技术:深入理解Feign_第17张图片

最终负载均衡交给loadBalancerContext来处理,即之前讲述的Ribbon,在这里不再重复。

总结

总到来说,Feign的源码实现的过程如下:

  • 首先通过@EnableFeignCleints注解开启FeignCleint
  • 根据Feign的规则实现接口,并加@FeignCleint注解
  • 程序启动后,会进行包扫描,扫描所有的@ FeignCleint的注解的类,并将这些信息注入到ioc容器中。
  • 当接口的方法被调用,通过jdk的代理,来生成具体的RequesTemplate
  • RequesTemplate在生成Request
  • Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp
  • 最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。
原文地址:https://dwz.cn/iXjQZJdr
作者:方志朋

你可能感兴趣的:(feign直接走熔断)