feign使用方法

一、简单介绍

  1. 工作原理
    1. 定义接口:开发人员通过定义一个Java接口,来描述要调用的RESTful API接口的请求方法、参数、请求头等信息。

    2. 生成代理类:在程序启动时,Fegin会根据定义的Java接口,动态生成一个代理类,并将其注入到Spring容器中。

    3. 发起请求:当应用程序调用代理类的方法时,Fegin会根据方法的注解信息,生成对应的HTTP请求,并用底层的HTTP客户端(比如OkHttp)发送给指定的服务提供者。

    4. 处理响应:当服务提供者返回响应结果时,Feign会将响应结果转换成Java对象,并返回给应用程序。

  2. Feign与OpenFeign区别
    1. 注解支持

            Feign仅支持JAX-RS(Java API for RESTful Web Services)注解,对Spring MVC注解不支持。OpenFeign支持Spring MVC注解,更贴近Spring开发体验;

    2. 编解码器

            Feign仅支持QueryStringEncoder、FormEncoder和JsonEncoder三种编解码器。OpenFeign内置了SpringEncoder和StringDecoder,支持更丰富的对象与HTTP请求的编解码,如集合、 maps等;

    3. contract

            Feign仅支持接口方法签名与url的映射,请求细节无法定制。OpenFeign支持SpringMvcContract,可以定制请求方法、参数绑定等细节;

    4. 拦截器

            Feign不支持请求与响应拦截器。OpenFeign支持RequestInterceptor和ResponseInterceptor,允许拦截并自定义Feign的请求与响应;

二、常用注解和参数

  1. @FeignClient:核心注解,声明一个Feign客户端。以下是该注解常用的属性:
    1. name/value:这两个的作用是一样的,指定的是调用服务的微服务名称,两个必须配置一个;

    2. url:指定调用服务的全路径。如果同时指定name和url属性:则以url属性为准,忽略name属性;

    3. configuration:指向FeignConfiguration配置类,该配置类如果加了@Component/@Service等注解会自动注入spring,作用于全局,可以同时指向多个,加载顺序从前往后,最后是全局的配置,但不代表相同配置后面的会覆盖前面的,需自行测试。

            (举例:全局配置和引用的配置都实现接口feign.RequestInterceptor,统一加了相同的请求头,如果headerName是Content-Type,最后的配置会覆盖前面的,否则是第一个生效)

            设置请求头源码:

    4. fallback:定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口;

    5. fallbackFactory:定义一个处理容错的工厂类,实现FallbackFactory,作用和fallback相同,但是灵活性更高,可以捕获到异常;

    6. path: 定义当前FeignClient的统一前缀,当我们项目中配置了server.context-path,server.servlet-path时使用(当方法里传入URI时不生效);

  2. @Headers、@HeaderMap、@RequestLine。feign的注解;
  3. @RequestMapping、@GetMapping、@PostMapping、 @PathVariable、@RequestParam、@RequestBody、@RequestHeader。这些都是org.springframework.web里面的注解,用法一样;

三、基本用法

  1. 如何添加请求头
    1. 在@RequestMapping注解中添加headers属性,或者在方法参数前面添加@RequestHeader注解,可以是一个也可以是多个;

      @RequestMapping(headers = {"headerName=headerValue"}) 
      String test(@RequestHeader("headerName") String headerValue, @RequestHeader Map<String, String> headerMap);
    2. FeignConfiguration实现接口RequestInterceptor

      public class TestFeignConfiguration implements RequestInterceptor { 
          @Override 
          public void apply(RequestTemplate requestTemplate) { 
              requestTemplate.header("headerName", "headerValue"); 
          } 
      }
    3. 在方法或类上面添加@Headers注解,或者在参数前面添加@HeaderMap注解,注意使用方式。

      @FeignClient(name = "feignCaller", url = "http://127.0.0.1:8080/", configuration = TestFeignConfiguration.class) 
      @Headers({"headerName: headerValue"}) 
      public interface FeignCaller { 
          // 因为配置了Contract,所以不能再用spring的注解,需要用feign自带的
          @RequestLine("GET /test4") 
          @Headers({"headerName: headerValue"}) 
          String test(@HeaderMap Map<String, String> headerMap); 
      }

      这两个注解是feign自带的,因为SpringCloud集成feign默认使用的是SpringMvcContract,所以直接使用会报错,如果想要使用需要配置自带的Contract,这时再用spring的注解就会启动报错;

      public class TestFeignConfiguration { 
          @Bean public Contract getContract(){ 
              return new feign.Contract.Default(); 
          } 
      }
  2. 如何配置请求路径
    @FeignClient(name = "feignCaller", path = "/feign", url = "http://127.0.0.1:8080/") 
    public interface FeignCaller { 
        @RequestMapping(value = "/test") String test(URI uri); 
    }
    1. 参数里直接传入URI优先级最高,如果方法上面的注解@RequestMapping的value属性有值,则会拼接上value值。(如上方法调用的接口就是{URI}/test);

    2. @FeignClient注解里面的url属性,在方法参数没有具体地址时生效。如果@FeignClient注解的path属性有值,则会拼接上path值,如果方法上面的注解@RequestMapping的value属性有值,则会再拼接上value值。(如上方法调用不传URI的情况下接口就是http://127.0.0.1:8080/feign/test);

    3. 如果@FeignClient没有url属性,则会使用name/value属性使用注册中心进行接口调用;

  3. FeignConfiguration使用
    1. 全局配置,添加@Component注解,会对所有feignClient生效;

      @Component 
      @EnableFeignClients 
      public class FeignConfiguration01 {}
    2. 非全局配置,只对@FeignClient注解中configuration属性指定该配置类的feignClient生效;

      public class FeignConfiguration02 {}
      @FeignClient(name = "feignCaller", url = "http://127.0.0.1:8080", configuration = FeignConfiguration02.class) 
      public interface FeignCaller { 
          @RequestMapping(value = "/test1") S
          tring test1(); 
      }
  4. 请求拦截器

    需要FeignConfiguration实现RequestInterceptor接口即可,上面添加请求头就是该方式;

  5. 性能优化
    1. 选择更高性能的HTTP客户端:如前所述,替换Feign默认的URLConnection,选择Apache HTTP Client、OkHttp等更高性能的HTTP客户端;

    2. 连接池优化:

      1. 合理设置连接池大小,不宜太大也不宜太小;

      2. 选择支持连接池复用的HTTP客户,如OkHttp;

      3. Ribbon也有连接池设置,与Feign的HTTP客户端配合优化。

    3. 超时优化:

      1. 合理设置Feign的连接超时和读取超时。连接超时不宜太长,读取超时根据服务调用耗时设置;

      2. Ribbon也有相应超时设置,与Feign协同优化。

    4. 服务线程池优化:

            Feign使用JDK默认线程池,我们可以进行定制:

      @Bean
      public ExecutorService feignExecutorService(){
          // 设置核心线程数,最大线程数,队列大小,释放资源时的延迟时间
          return new ThreadPoolExecutor(xx, yy, zz, TimeUnit.SECONDS, 
              new LinkedBlockingQueue<Runnable>(zzz), 
              new NamedThreadFactory("feign"));
      }
    5. 重试优:

      1. 合理设置Feign的重试次数和时间间隔;

      2. 区分对不同服务的重试策略,防止重试过度导致系统资源消耗过大。

    6. GZIP压缩:

                    Feign支持对请求和响应进行GZIP压缩,以提高网络传输性能。可以在配置文件里开启。

四、配置文件

  1. 日志输出

        Feign支持日志记录,我们可以设置日志级别以查看Feign的调用详情,设置为ALL,则会展示完整的请求、响应日志详情;

    feign:
      client: 
        config:
          default: 
            loggerLevel: FULL 
  2. 修改http客户端

        Feign默认使用JDK原生的URLConnection发送HTTP请求,我们也可以选择更换HTTP客户端,如Apache HTTP Client、OkHttp等;

    feign:
      client: 
        config:
          default: 
            okhttp:
              enabled: true # 开启OkHttp
  3. 设置最大连接数和超时时间
    feign:
      httpclient:
        enabled: true
        max-connections: 1000
        max-connections-per-route: 2000
      client:
        config:
          default:
            readTimeout: 10000
            connectTimeout: 1000
  4. 请求响应压缩

        可以对请求和响应进行配置是否开启压缩,以及请求压缩类型和最小压缩大小等;

    feign:
      compression:
        response:
          enabled: true
        request:
          enabled: true
          # 支持压缩的类型
          mime-types: text/xml,application/xml,application/json
          # 压缩触发的最小请求大小
          min-request-size: 2048

五、Feign高可用方案

          对于一个微服务系统来说,服务调用是非常重要的一个环节,Feign作为一个重要的调用组件,其高可用性直接影响整个系统的高可用。这里给出一些提高Feign高可用的方案:

        服务发现与注册

            Feign常与Eureka、Dubbo等服务注册中心协同使用,这些服务注册中心本身也支持集群部署,可以提高Feign服务调用的高可用性;

        Ribbon负载均衡

          Feign内置的Ribbon组件,我们可以设置多个服务实例,并选择合适的负载均衡策略,避免单点故障;

        Hystrix容错保护

            Hystrix可以进行线程隔离、熔断等策略保护Feign,避免在高并发下服务被过载。熔断机制可以快速失败,避免操作阻塞;

        Http客户端连接池

            使用连接池,如Apache HTTP Client、OKHttp等,可以进行连接复用,避免每次调用都建立新的连接。并且这些客户端本身也支持高可用配置,如设置多个Url地址;

        超时与重试机制

            合理设置Feign的连接超时、读取超时时间,可以快速发现服务问题并快速失败,避免资源占用过长时间。配合重试机制,在一定次数后快速返回,防止长时间的不可用服务导致系统不可用;

        熔断与限流

            除Hystrix外,可以使用Resilience4J等开源组件进行更加全面和强大的熔断、限流、重试。限流可以防止突发高流量导致系统不可用;

        服务跟踪

          使用组件如Zipkin进行服务调用链路跟踪,一旦出现高延迟或不可用服务,可以快速定位问题所在;

        降级策略

            为Feign接口指定Fallback以及合适的降级策略,在服务不可用时提供备选方案,避免不可用服务导致依赖服务完全不可用;

        日志记录与监控

            合理配置Feign日志级别,并结合ELK等日志收集工具进行监控。一旦服务有异常状况,可以快速发现并定位问题。

          综上,Feign高可用需要多方面的保障和运维,需要与服务注册中心、熔断限流组件、链路跟踪组件、监控日志组件等协同配合,共同提高Feign和依赖其的整个微服务系统的高可用性。

六、源码分析

  理解Feign的源码,有助于我们更深入理解其工作原理,从而合理使用和定制Feign。这里简要分析Feign的源码:

  1. Feign类:Feign类是Feign的入口,主要工作是

    1. 解析Feign注解,获取接口方法与url映射关系,请求类型等信息;

    2. 构建ReflectiveFeign类,封装接口方法与请求细节的映射;

    3. 构建Feign.Builder,用于创建Feign实例;

    4. 创建Logger用于记录Feign日志;

    5. 绑定Contract契约,默认是SpringMvcContract;

  2. ReflectiveFeign类

    1. 维护Feign接口方法与请求模板(RequestTemplate)的映射;

    2. 调用接口方法时,查找请求模板,使用请求参数构造URL,发起HTTP请求;

    3. 将响应结果转换为接口方法 defined 返回类型,返回给调用方;

  3. Contract接口与SpringMvcContract

    1. Contract接口定义了诸如生成请求模板、构造参数值到模板变量等规则;

    2. SpringMvcContract实现了Spring MVC注解方式,将方法、参数注解转化为请求模板变量与值;

  4. Client接口与Client.Default实现

    1. Client接口定义了发起HTTP请求的方法。Feign使用构建器模式,允许我们选择不同Client实现来发送请求;

    2. Client.Default实现了使用JDK原生URLConnection发送HTTP请求。我们可以实现自定义Client,如使用OKHttp等;

  5. Encoder和Decoder
    1. Encoder负责对请求参数进行编码,默认使用SpringEncoder对参数进行JSON编码;

    2. Decoder负责对响应结果进行解码,默认使用SpringDecoder对JSON响应进行解码;

  6. Logger和LoggingInterceptor
    1. Logger定义了记录Feign日志的规范,有4个级别:NONE、BASIC、HEADERS、FULL;

    2. LoggingInterceptor拦截Feign请求与响应,将详细信息记录为Feign日志, logfile可指定日志记录位置;

  7. Retryer接口
    1. 定义重试策略,Feign内置支持backoff、exponential backoff重试策略。我们也可以自定义Retryer实现。

  这些是Feign的主要组成部分, Feign的高效与灵活正是因为这些组件采用接口设计,允许我们灵活选择与替换。理解这些组件的作用与关系,有助于我们使用Feign的源码进行定制化开发。

七、验证

  1. FeignConfiguration相关验证(同时验证配置生效范围和加载顺序、修改默认Contract对启动的影响、实现RequestInterceptor接口方式来添加请求头的顺序问题)
    1. case1:添加一个全局配置,添加一个feignClient不做任何引用,期望配置生效;

    2. case2:添加一个全局配置,内容为空,再添加一个非全局配置,添加一个feignClient不做任何引用,期望配置不生效;

    3. case3:分别添加一个全局和非全局的配置,添加一个feignClient不做任何引用,期望全局配置生效,非全局配置不生效;

    4. case4:分别添加一个全局和非全局的配置,添加一个feignClient引用非全局配置,期望全局配置生效,非全局配置也生效;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值