Springcloud OpenFeign 详解

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Springcloud OpenFeign 详解

 一、概述

OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,整合了hystrix,同时,可以和Eureka和ribbon配合使用,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

官网:Spring Cloud OpenFeign

OpenFegin中的两个常用注解

@FeignClient: 用于通知Feign组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@Autowired注入。

@FeignClient标签的常用属性如下:

    • name/value:指定的是调用服务的微服务名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
      • contextId:指定beanID
        • url: url指定调用服务的全路径,一般用于调试,可以手动指定@FeignClient调用的地址
          • decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
            • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
              • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
                • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
                  • path: 定义当前FeignClient的统一前缀

                  @EnableFeignClients: Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。

                  二、Feign和openFeign有什么区别?

                  Feign

                  openFiegn

                  Feign是SpringCloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务

                  OpenFeign是SpringCloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

                  三、代码实现:

                  1、POM文件引入依赖:

                  <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-openfeign</artifactId>
                  </dependency>

                  image.gif

                  2、添加注解@EnableFeignClients开启openFeign功能

                  @SpringBootApplication
                  @EnableFeignClients
                  public class Application {
                      public static void main(String[] args) {
                          SpringApplication.run(Application.class, args);
                      }
                  }

                  image.gif

                  3、 新建openFeign接口

                  新建一个openFeign接口,使用@FeignClient注解标注,如下

                  @FeignClient("stores")
                  public interface StoreClient {
                      @RequestMapping(method = RequestMethod.GET, value = "/stores")
                      List<Store> getStores();
                      @RequestMapping(method = RequestMethod.GET, value = "/stores")
                      Page<Store> getStores(Pageable pageable);
                      @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
                      Store update(@PathVariable("storeId") Long storeId, Store store);
                      @RequestMapping(method = RequestMethod.DELETE, value = "/stores/{storeId:\\d+}")
                      void delete(@PathVariable Long storeId);
                  }

                  image.gif

                  3、openFeign如何传参

                  1. 传递JSON数据

                  如果是 POST 请求,而且是对象集合等参数,在Spring Boot 中通过@RequestBody标识入参

                  @PostMapping("createOrder")
                  public String createOrder(@RequestBody Order order ){
                      System.out.println(order);
                      return "ok";
                  }

                  image.gif

                  2. POJO表单传参

                  Spring Cloud OpenFeign 提供了一个等效的注释,它 用于将 POJO 或 Map 参数注释为查询参数映射。@SpringQueryMap

                  Order createOrder(@SpringQueryMap Order order);

                  下图是官方给出的实例

                  // Params.java
                  public class Params {
                      private String param1;
                      private String param2;
                      // [Getters and setters omitted for brevity]
                  }

                  image.gif

                  以下假装客户端通过注释使用该类:Params@SpringQueryMap

                  @FeignClient("demo")
                  public interface DemoTemplate {
                      @GetMapping(path = "/demo")
                      String demoEndpoint(@SpringQueryMap Params params);
                  }

                  image.gif

                  3.URL中携带参数

                  通过 URL 传参数,GET 请求,参数列表使用@PathVariable(“”)

                  服务提供者代码如下:

                  @RestController
                  @RequestMapping("/openfeign/orderprovider")
                  public class OpenFeignOrderProviderController {
                      @GetMapping("/getOrder/{id}")
                      public String getOrder(@PathVariable("id")Integer id){
                          return "accept one msg id="+id;
                  }

                  image.gif

                  consumer消费者openFeign接口如下:

                  @FeignClient(value = "openFeign-orderprovider")
                  public interface OpenFeignService {
                      @GetMapping("/openfeign/orderprovider/getOrder/{id}")
                      String getOrder(@PathVariable("id")Integer id);
                  }

                  image.gif

                  4、超时如何处理

                  ReadTimeout: 值的是建立链接所用的时间,适用于网络状况正常的情况下, 两端链接所用的时间

                  ConectTimeout: 指的是建立链接后从服务器读取可用资源所用的时间

                  openFeign设置超时时间非常简单,只需要在配置文件中配置,如下:

                  feign:
                    client:
                      config:
                        ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
                        default:
                          connectTimeout: 1000
                          readTimeout: 1000

                  image.gif

                  5、Feign logging

                  为每个创建的 Feign 客户端创建一个记录器。默认情况下,记录器的名称是用于创建 Feign 客户端的接口的完整类名。日志记录仅响应级别:DEBUG。

                  openFeign的日志级别如下:

                  NONE:默认的,不显示任何日志;

                  BASIC:仅记录请求方法、URL、响应状态码及执行时间;

                  HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;

                  FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。

                  配置方式:

                  1. 配置文件application.yml:

                  logging.level.project.user.UserClient: DEBUG

                  image.gif

                  2.自定义一个配置类,在其中设置日志级别

                  @Configuration
                  public class FooConfiguration {
                      @Bean
                      Logger.Level feignLoggerLevel() {
                          return Logger.Level.FULL;
                      }
                  }

                  image.gif

                  6、对@RefreshScope支持

                  如果启用了 Feign 客户端刷新,则使用以下命令创建每个 Feign 客户端:

                    • feign.Request.Options作为刷新范围的 Bean。这意味着像connectTimeout and readTimeout 等属性可以针对任何 Feign 客户端实例刷新。
                      • 在 下换行的网址org.springframework.cloud.openfeign.RefreshableUrl。这意味着 Feign 客户端的 URL(如果已定义)spring.cloud.openfeign.client.config.{feignName}.url 属性,可以针对任何 Feign 客户端实例刷新。

                      可以通过 刷新这些属性。POST /actuator/refresh

                      默认情况下,Feign 客户端中的刷新行为处于禁用状态。使用以下属性启用刷新行为:

                      spring.cloud.openfeign.client.refresh-enabled=true

                      image.gif

                      7、假请求/响应压缩

                      您可以考虑为您的启用请求或响应 GZIP 压缩 佯装请求。您可以通过启用以下属性之一来执行此操作:

                      spring.cloud.openfeign.compression.request.enabled=true
                      spring.cloud.openfeign.compression.response.enabled=true

                      image.gif

                      假请求压缩为您提供的设置类似于您可能为 Web 服务器设置的设置:

                      spring.cloud.openfeign.compression.request.enabled=true
                      spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
                      spring.cloud.openfeign.compression.request.min-request-size=2048

                      image.gif

                      这些属性允许您选择压缩媒体类型和最小请求阈值长度。

                      8、Feign Spring Cloud CircuitBreaker Fallbacks

                      Spring Cloud CircuitBreaker支持回退的概念:当链路断开或出现错误时执行的默认代码路径。要为给定的@FeignClient启用回退,请将回退属性设置为实现回退的类名。您还需要将您的实现声明为Springbean:

                      @FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
                          protected interface TestClient {
                              @RequestMapping(method = RequestMethod.GET, value = "/hello")
                              Hello getHello();
                              @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
                              String getException();
                          }
                          @Component
                          static class Fallback implements TestClient {
                              @Override
                              public Hello getHello() {
                                  throw new NoFallbackAvailableException("Boom!", new RuntimeException());
                              }
                              @Override
                              public String getException() {
                                  return "Fixed response";
                              }
                          }

                      image.gif

                      如果需要访问导致回退触发的原因,可以在@FeignClient中使用fallbackFactory属性:

                      @FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/",
                                  fallbackFactory = TestFallbackFactory.class)
                          protected interface TestClientWithFactory {
                              @RequestMapping(method = RequestMethod.GET, value = "/hello")
                              Hello getHello();
                              @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
                              String getException();
                          }
                          @Component
                          static class TestFallbackFactory implements FallbackFactory<FallbackWithFactory> {
                              @Override
                              public FallbackWithFactory create(Throwable cause) {
                                  return new FallbackWithFactory();
                              }
                          }
                          static class FallbackWithFactory implements TestClientWithFactory {
                              @Override
                              public Hello getHello() {
                                  throw new NoFallbackAvailableException("Boom!", new RuntimeException());
                              }
                              @Override
                              public String getException() {
                                  return "Fixed response";
                              }
                          }

                      image.gif

                      9、Feign and @Primary

                      当将Feign与Spring Cloud CircuitBreaker回退一起使用时,ApplicationContext中存在多个相同类型的bean。这将导致@Autowired无法工作,因为没有确切的一个bean,或者一个被标记为primary。为了解决这个问题,Spring Cloud OpenFeign将所有Feign实例标记为@Primary,这样Spring Framework就会知道要注入哪个bean。在某些情况下,这可能是不可取的。若要关闭此行为,请将@FeignClient的主属性设置为false:

                      @FeignClient(name = "hello", primary = false)
                      public interface HelloClient {
                          // methods here
                      }

                      image.gif

                      10、Feign Caching

                      如果使用@EnableCaching annotation,则会创建并注册CachingCapability bean,以便您的Feign客户端在其接口上识别@Cache*annotations:

                      public interface DemoClient {
                          @GetMapping("/demo/{filterParam}")
                          @Cacheable(cacheNames = "demo-cache", key = "#keyParam")
                          String demoEndpoint(String keyParam, @PathVariable String filterParam);
                      }

                      image.gif

                      您也可以通过属性spring.cloud.openfacy.cache.enabled=false禁用该功能。




                      Doker 技术人的数码品牌!!!

                      文章下方有交流学习区!一起学习进步!也可以前往官网,加入官方微信交流群!!!

                      你的支持和鼓励是我创作的动力❗❗❗

                      官网:Doker 多克; 官方旗舰店首页-Doker 多克官方旗舰店 全品8.5折优惠,购前请和店小二说明来自阿里云!!!

                      相关实践学习
                      日志服务之使用Nginx模式采集日志
                      本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
                      目录
                      相关文章
                      |
                      22天前
                      |
                      负载均衡 Java 开发者
                      深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
                      深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
                      68 5
                      |
                      6月前
                      |
                      负载均衡 Java API
                      Java一分钟之-Spring Cloud OpenFeign:声明式服务调用
                      【6月更文挑战第9天】Spring Cloud OpenFeign是声明式服务调用库,简化了微服务间调用。通过动态代理,它允许开发者用Java接口调用HTTP服务,支持服务发现、负载均衡。本文介绍了OpenFeign的基本概念,展示了如何添加依赖、开启客户端和定义服务接口。还讨论了接口调用失败、超时重试和日志配置等问题及其解决方案,并提供了自定义Feign配置的代码示例。通过学习,读者可以更好地在微服务架构中使用OpenFeign进行服务通信。
                      347 4
                      |
                      6月前
                      springCloud之服务降级熔断Hystrix、OpenFeign
                      springCloud之服务降级熔断Hystrix、OpenFeign
                      370 0
                      |
                      2月前
                      |
                      负载均衡 Java API
                      【Spring Cloud生态】Spring Cloud Gateway基本配置
                      【Spring Cloud生态】Spring Cloud Gateway基本配置
                      57 0
                      |
                      4月前
                      |
                      Java Spring
                      【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
                      【Azure Spring Cloud】Spring Cloud Azure 4.0 调用Key Vault遇见认证错误 AADSTS90002: Tenant not found.
                      |
                      4月前
                      |
                      Java Spring 容器
                      【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
                      【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.use 的指标的疑问及OOM
                      |
                      4月前
                      |
                      存储 Java Spring
                      【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
                      【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
                      |
                      4月前
                      |
                      SQL Java 数据库连接
                      【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
                      【Azure Spring Cloud】Azure Spring Cloud connect to SQL using MSI
                      |
                      4月前
                      |
                      Java 开发工具 Spring
                      【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
                      【Azure Spring Cloud】使用azure-spring-boot-starter-storage来上传文件报错: java.net.UnknownHostException: xxxxxxxx.blob.core.windows.net: Name or service not known
                      |
                      4月前
                      |
                      NoSQL Java Redis
                      【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常
                      【Azure Spring Cloud】Java Spring Cloud 应用部署到Azure上后,发现大量的 java.lang.NullPointerException: null at io.lettuce.core.protocol.CommandHandler.writeSingleCommand(CommandHandler.java:426) at ... 异常