注册用户享全站资源 并成为粉丝 不定时福利发放
 

深入理解Feign之源码解析

22
发表时间:2018-09-04 17:48

什么是Feign

Feign是受到Retrofit,JAXRS-2.0和WebSocket的影响,它是一个jav的到http客户端绑定的开源项目。 Feign的主要目标是将Java Http 客户端变得简单。

写一个Feign

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

其自定义配置文件如下,当然也可以不写配置文件,用默认的即可:

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

FeignClient注解被@Target(ElementType.TYPE)修饰,表示FeignClient注解的作用目标在接口上;
@Retention(RetentionPolicy.RUNTIME),注解会在class字节码文件中存在,在运行时可以通过反射获取到;@Documented表示该注解将被包含在javadoc中。

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

代码如下:

重写配置:

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

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

Feign的工作原理

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

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

程序启动后通过包扫描,当类有@FeignClient注解,将注解的信息取出,连同类名一起取出,赋给BeanDefinitionBuilder,然后根据BeanDefinitionBuilder得到beanDefinition,最后beanDefinition式注入到ioc容器中,源码如下:


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



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



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



Client组件

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

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


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



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




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

在pom文件加上:


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



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

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


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



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



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



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

总结

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

  • 首先通过@EnableFeignCleints注解开启FeignCleint

  • 根据Feign的规则实现接口,并加@FeignCleint注解

  • 程序启动后,会进行包扫描,扫描所有的@ FeignCleint的注解的类,并将这些信息注入到ioc容器中。

  • 当接口的方法被调用,通过jdk的代理,来生成具体的RequesTemplate

  • RequesTemplate在生成Request

  • Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp

  • 最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡。



会员登录

会员登录

登录免费下载全站资源

获取验证码
登录
登录
开发简历

开发简历

简历模板网站自取

入坑需谨慎

入坑需谨慎

高薪完全靠自己

微信赞助-Java帮帮社区

微信赞助-Java帮帮社区

非盈利性学习社区

支付宝赞助-Java帮帮社区

支付宝赞助-Java帮帮社区

将分享做到极致

大公司资讯
文章附图

近日,在美国推出满一年的Facebook视频服务Watch,宣布正式向全球推广,这预示着视频领域中,YouTube...

文章附图

据彭博社北京时间9月19日报道,科技行业最引人注目的法律大战可能正在进入尾声。据高通CEO史蒂夫·莫伦科夫(Ste...

Java帮帮公众号生态

Java帮帮公众号生态

总有一款适合你

Java帮帮-微信公众号

Java帮帮-微信公众号

将分享做到极致

Python帮帮-公众号

Python帮帮-公众号

人工智能,爬虫,学习教程

大数据驿站-微信公众号

大数据驿站-微信公众号

一起在数据中成长

九点编程-公众号

九点编程-公众号

深夜九点学编程

程序员服务区-公众号

程序员服务区-公众号

吃喝玩乐,听学吐画

Java帮帮学习群生态

Java帮帮学习群生态

总有一款能帮到你

Java学习群

Java学习群

与大牛一起交流

大数据学习群

大数据学习群

在数据中成长

九点编程学习群

九点编程学习群

深夜九点学编程

python学习群

python学习群

人工智能,爬虫

测试学习群

测试学习群

感受测试的魅力

Java帮帮生态承诺

Java帮帮生态承诺

一直坚守,不负重望

初心
勤俭
诚信
正义
分享
合作品牌 非盈利生态-优质内容分享传播者
关于我们
友链申请
友链交换:加帮主QQ2524138991 留言即可 24小时内答复  
全站内容非商业用途,内容来源于网友,并遵循 CC BY-NC 4.0 许可,如有异议请联系客服。
会员登录
获取验证码
登录
登录
我的资料
留言
回到顶部