1.Feign简介
(1)Feign是由Retrofit,JAXRS-2.0和WebSocket启发的一个java到http客户端绑定
(2) Feign的主要目标是将Java Http Clients变得简单
<1>Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单
<2>使用Feign,只需要创建一个接口并注解@FeignClient
<3>@FeignClient具有可插拔的注解特性,可使用Feign注解和JAX-RS注解
(3)Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果
(4)Feign的源码地址:https://github.com/OpenFeign/feign
2.实现一个Feign
(1)简单的实现一个Feign客户端,首先通过@FeignClient
<1>value为调用其他服务的名称
<2>FeignConfig.class为FeignClient的配置文件
(2)代码实现如下:
<1>定义接口
@FeignClient(value = "service-hi",configuration = FeignConfig.class)
public interface SchedualServiceHi {
@GetMapping(value = "/hi")
String sayHiFromClientOne(@RequestParam(value = "name") String name);}
<2>FeignClient配置文件如下:
@Configuration
public class FeignConfig {
@Bean
public Retryer feignRetryer() {
return new Retryer.Default(100, SECONDS.toMillis(1), 5);}}
3.FeignClient的配置:
(1)默认的配置类为FeignClientsConfiguration
<1>这个类在spring-cloud-netflix-core的jar包下
<2>它是一个配置类,注入了很多的相关配置的bean
2.1.feignRetryer、FeignLoggerFactory、FormattingConversionService等
2.2.还包括了Decoder、Encoder、Contract
2.2.1.如果这三个bean在没有注入的情况下,会自动注入默认的配置
2.2.1.1.Decoder: ResponseEntityDecoder(这是对SpringDecoder的封装)
2.2.1.2.Encoder: SpringEncoder
2.2.1.3.Logger: Slf4jLogger
2.2.1.4.Contract: SpringMvcContract
2.2.1.5.Feign.Builder feignBuilder: HystrixFeign.Builder
(2)重写配置类FeignClientsConfiguration
<1>重写FeignClientsConfiguration中的bean,从而达到自定义配置的目的
<2>FeignClientsConfiguration默认重试次数为Retryer.NEVER_RETRY即不重试
<3>那么希望做到重写,代码示例如下:
@Configuration
public class FeignConfig {
@Bean
public Retryer feignRetryer() {
/**
*更改了该FeignClient的重试次数
*重试间隔为100ms,最大重试时间为1s,重试次数为5次
*/
return new Retryer.Default(100, SECONDS.toMillis(1), 5);}}
4.Feign的工作原理
(1)feign是一个伪客户端,即它不做任何的请求处理
(2)Feign通过处理注解生成request,从而实现简化HTTP API开发的目的
<1>开发人员可以使用注解的方式定制request api模板
<2>在发送httprequest请求前,feign通过处理注解方式替换掉request模板中的参数
<3>这种实现方式显得更为直接、可理解
(3)通过包扫描注入FeignClient的bean
<1>该源码在FeignClientsRegistrar类
1.1.首先在启动配置上检查是否有@EnableFeignClients注解
1.2.如果有该注解,则开启包扫描,扫描被@FeignClient注解接口
1.3.扫描到FeignClient后,将信息取出,以bean的形式注入到ioc容器中
1.4.注入bean之后,通过jdk的代理
1.5.当请求Feign Client的方法时会被拦截,代码在ReflectiveFeign类
1.6.在SynchronousMethodHandler类进行拦截处理
1.7.当被拦截会根据参数生成RequestTemplate对象,该对象就是http请求的模板
<2>其中有个executeAndDecode()方法
2.1.该方法是通RequestTemplate生成Request请求对象
2.2.然后根据用client获取response
5.Client组件
(1)Client组件是一个非常重要的组件
<1>Feign最终发送request请求以及接收response响应,都是由Client组件完成的
<2>Client的实现类,只要有Client.Default
<3>该类由HttpURLConnnection实现网络请求,另外还支持HttpClient、Okhttp
(2)FeignRibbonClient的自动配置类FeignRibbonClientAutoConfiguration
<1>主要在工程启动的时候注入一些bean
<2>在缺失配置feignClient的情况下,会自动注入new Client.Default(),跟踪Client.Default()源码
<3>它使用的网络请求框架为HttpURLConnection
(3)在Feign中使用HttpClient
<1>只需要在pom文件加上HttpClient的classpath就行了
<2>pom.xml配置如下:
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>RELEASE</version>
</dependency>
(4)如果想要Feign使用Okhttp,则只需要在pom文件上加上feign-okhttp的依赖:
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>RELEASE</version>
</dependency>
6.Feign负载均衡的实现
(1)通过上述的FeignRibbonClientAutoConfiguration类配置Client的类型的时候
<1>Client的类型:httpurlconnection,okhttp和httpclient
<2>最终向容器注入的是LoadBalancerFeignClient,即负载均衡客户端
<3>其中有个executeWithLoadBalancer()方法,即通过负载均衡的方式请求
<4>服务在submit()方法上
4.1.点击submit进入具体的方法,这个方法是LoadBalancerCommand的方法
4.2.代码中有个selectServe(),该方法是选择服务的进行负载均衡的方法
(2)最终负载均衡交给loadBalancerContext来处理,即之前讲述的Ribbon
7.总结
(1)总到来说,Feign的源码实现的过程如下:
<1>首先通过@EnableFeignCleints注解开启FeignCleint
<2>根据Feign的规则实现接口,并加@FeignCleint注解
<3>程序启动后,会进行包扫描,扫描所有的@FeignCleint的注解的类,并将这些信息注入到ioc容器中
<4>当接口的方法被调用,通过jdk的代理,来生成具体的RequesTemplate
<5>RequesTemplate在生成Request
<6>Request交给Client去处理
6.1.其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp
<7>最后Client被封装到LoadBalanceClient类,该类结合类Ribbon做到了负载均衡
(2)参考文献:
https://diplr.org/the-netflix-stack-using-spring-boot-part-3-feign/