目录

Feign 和OpenFeign

Feign

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。

Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务Feign本身不支持Spring MVC的注解,它有一套自己的注解

OpenFeign

OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等,是一个轻量级的Http封装工具对象,大大简化了Http请求,使得我们对服务的调用转换成了对本地接口方法的调用。

OpenFeign 的 @FeignClient 可以解析SpringMVC的 @RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务

openFeign的优势

  1. 集成了Ribbon的负载均衡功能
  2. 集成Hystrix的熔断器功能
  3. 支持请求压缩
  4. 大大简化了远程调用的代码,同时功能还增强啦
  5. 以更加优雅的方式编写远程调用代码,并简化重复代码

OpenFeign应用

1. 导入依赖

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

2. 使用

创建Feign接口

@FeignClient(value = "xx-template-service")//value = "xx-template-service"指定服务的名字
public interface DriverFeign { /**
* demo feign 接口
*/
@PutMapping(value = "/driver/status")
Driver status(String id, Integer status);
}

Feign会通过动态代理,帮我们生成实现类。

注解@FeignClient声明Feign的客户端,注解value指明服务名称接口定义的方法,采用SpringMVC的注解。Feign会根据注解帮我们生成URL地址

FeignClient 注解参数

  • name/value:指定FeignClient的名称,如果项目使用了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的统一前缀

注意事项

  1. 在使用fallback、fallbackFactory属性时,需要使用@Component注解,保证fallback类被Spring容器扫描到
  2. 在使用FeignClient时,Spring会按name创建不同的ApplicationContext,通过不同的Context来隔离FeignClient的配置信息, 在使用配置类时,不能把配置类放到Spring App Component scan的路径下,否则,配置类会对所有FeignClient生效.

启用OpenFeign

我们需要在服务的启动类上开启 OpenFeign ,只需要在 **Application 启动类上添加 @EnableFeignClients即可。

3. 日志配置

logging:
level:
xx.template.cloud.web.service.feign.ServiceServiceFeign: debug

通过loggin.level.xx=debug来设置日志级别。然而这个对Feign客户端不会产生效果。因为@FeignClient注解修饰的客户端在被代理时,都会创建一个新的Feign.Logger实例。我们需要额外指定这个日志的级别才可以。

  /**
* feign 日志级别配置
* @return
*/
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}

或者在配置文件中配置

feign:
client:
config:
# 全局配置
default:
loggerLevel: full

Feign支持4种级别:

NONE:不记录任何日志,默认值

BASIC:仅记录请求的方法,URL以及响应状态码和执行时间

HEADERS:在BASIC基础上,额外记录了请求和响应的头信息

FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据

4. 数据压缩

用户在网络请求过程中,如果网络不佳、传输数据过大,会造成体验差的问题,我们需要将传输数据压缩提升体验。SpringCloud OpenFeign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。

在客户端中配置数据压缩

feign:
compression:
request:
enabled: true # 开启请求压缩
response:
enabled: true # 开启响应压缩

也可以对请求的数据类型,以及触发压缩的大小下限进行设置

feign:
compression:
request:
enabled: true # 开启请求压缩
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
min-request-size: 2048 # 设置触发压缩的大小下限
#以上数据类型,压缩大小下限均为默认值
response:
enabled: true # 开启响应压缩

OpenFeign高级应用

OpenFeign熔断降级的两种方式-降级方法和降级工厂

首先在配置文件中配置如下,开启熔断降级

feign.hystrix.enabled=true
  1. Feign 定义降级方法

    feign接口定义

    /**
    * FeignClient 注解的 fallback 属性指定降级类
    */
    @FeignClient(name = "xx-template-cloud-service", fallback = ServiceServiceFeignFallBack.class)
    public interface ServiceServiceFeign { @GetMapping("/order/getOrder")
    Result getOrder(String id);
    }

    feign接口降级方法定义

    @Slf4j
    @Component
    class ServiceServiceFeignFallBack implements ServiceServiceFeign { @Override
    public Result getOrder(String id) {
    log.error("Feign接口熔断 熔断方式:ServiceServiceFeignFallBack");
    return Result.error("500", "Feign接口熔断");
    }
    }
  2. Feign 定义降级工厂

    feign接口定义

    /**
    * FeignClient 注解的 fallback 属性指定降级类
    */
    @FeignClient(name = "xx-template-cloud-service", fallback = UserCenterFeignClientFallbackFactory.class)
    public interface ServiceServiceFeign { @GetMapping("/order/getOrder")
    Result getOrder(String id);
    }

    feign接口降级工厂定义

    @Component
    @Slf4j
    class UserCenterFeignClientFallbackFactory implements FallbackFactory<ServiceServiceFeign> { @Override
    public ServiceServiceFeign create(Throwable cause) {
    return new ServiceServiceFeign() {
    @Override
    public Result getOrder(String id) {
    log.error("Feign接口熔断,熔断方式:UserCenterFeignClientFallbackFactory");
    return Result.error("500", "Feign接口熔断");
    }
    };
    }
    }

踩坑指南

坑一:Http Client

OpenFeign默认使用jdk自带的HttpURLConnection,我们知道HttpURLConnection没有连接池、性能和效率比较低,如果采用默认,很可能会遇到性能问题导致系统故障

  1. 可以采用Apache HttpClient

    注意feign-httpclient的版本,如果和Open Feign 不兼容可能会报original request is required异常

    <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>10.10.1</version>
    </dependency>
    feign.httpclient.enabled=true
  2. 也可以采用OkHttpClient

    <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>10.2.0</version>
    </dependency>
    feign.okhttp.enabled=true

ribbon中的Http Client

通过OpenFeign作为注册中心的客户端时,默认使用Ribbon做负载均衡,Ribbon默认也是用jdk自带的HttpURLConnection,需要给Ribbon也设置一个Http client,比如使用okhttp,在properties文件中增加下面配置

ribbon.okhttp.enabled=true

坑二:全局超时时间

OpenFeign可以设置超时时间,简单粗暴,设置一个全局的超时时间。如果不配置超时时间,默认是连接超时10s,读超时60s。

feign.client.config.default.connectTimeout=2000
feign.client.config.default.readTimeout=60000

但是如果某个服务的并发量很高,服务的超时时间过长会导致占用大量连接资源,导致系统崩溃,要防止这样的故障发生,最好的做法就是给服务单独设置超时时间。

当然,如果开启熔断后,不配置hystrix和ribbon的超时时间,那么Hystrix与ribbon的默认请求超时时间都是1秒,建议配置Hystrix的超时时间要大于ribbon的超时时间,否则会在接口调用还未完成的时候直接进入回调方法。

# 开启熔断
feign.hystrix.enabled: true

坑三:单服务设置超时时间

上文所述,对单个服务设置超时时间。

feign.client.config.serviceA.connectTimeout=2000
feign.client.config.serviceA.readTimeout=60000

但是如果serviceA中有多个接口,其中X接口又调用serviceB的Feign接口,为了保证X接口请求不被单服务超时时间影响,需要单独对X接口设置超时时间。

几个组件的关系

hystrix+ribbon。hystrix在最外层,然后再到Ribbon,最后里面的是http请求。所以说。hystrix的熔断时间必须大于ribbon的 ( ConnectTimeout + ReadTimeout )。而如果ribbon开启了重试机制,还需要乘以对应的重试次数(注意这里的重试可以是ribbon的重试也可能是feign的重试),保证在Ribbon里的请求还没结束时,Hystrix的熔断时间不会超时。

遇到的问题

1. 使用Spring MVC注解,但请求方式不正确

  • 参数没有通过注解指定,此时的参数会自动封装到body中,Feign检测到body里面有请求参数就会默认使用POST请求。
  • Feign默认使用的是POST方法,如果想使用GET方法,需要在配置文件中设置spring.cloud.openfeign.client.config.default.method.name=get。
  • 如果使用了Spring Cloud Netflix Feign,那么可能是因为您的应用程序使用了Spring Cloud Netflix Ribbon来处理HTTP负载均衡。在这种情况下,您需要确保Ribbon的配置正确,并且不会影响Feign的GET请求。

2. 使用nacos做注册中心,Feign调用时拉取的服务列表为空

我用的spring cloud版本是Hoxton.SR8

    <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

原因是Feign 在spring cloud Hoxton.M2版本之后,不再使用ribbon,所以我们在pom文件中还需要导入loadbalancer依赖,并排除掉nacos的ribbon依赖。

        <!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.1</version>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

并在配置文件中添加


spring.cloud.loadbalancer.ribbon.enabled: false

Spring Cloud OpenFeign 的使用及踩坑指南的更多相关文章

  1. Spring WebSocket踩坑指南

    Spring WebSocket踩坑指南 本次公司项目中需要在后台与安卓App间建立一个长连接,这里采用了Spring的WebSocket,协议为Stomp. 关于Stomp协议这里就不多介绍了,网上 ...

  2. Feign 系列(05)Spring Cloud OpenFeign 源码解析

    Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/ ...

  3. Spring Cloud OpenFeign使用教程

    文章目录 Spring Cloud OpenFeign Demo 怎么配置OpenFeignServer 怎么配置OpenFeignClient 多个参数传递问题 FeignClient的日志问题 多 ...

  4. SpringCloud升级之路2020.0.x版-29.Spring Cloud OpenFeign 的解析(1)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在使用云原生的很多微服务中,比较小规模的可能直接依靠云服务中的负载均衡器进行内部域名与服务 ...

  5. 微服务生态组件之Spring Cloud OpenFeign详解和源码分析

    Spring Cloud OpenFeign 概述 Spring Cloud OpenFeign 官网地址 https://spring.io/projects/spring-cloud-openfe ...

  6. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  7. 树莓派4B踩坑指南 - (15)搭建在线python IDE

    今天想在树莓派上自己搭一个在线的python IDE,于是找到了一篇教程--Fred913大神的从头开始制作OJ-在线IDE的搭建 自己尝试动手做了一下, 还是发现不少细节需要注意, 记录在此 如果不 ...

  8. 正则表达式 test 踩坑指南

    正则表达式 test 踩坑指南 test 只能使用一次,第二次返回的是错误结果! reg = /edg|edge/g; /edg|edge/g reg.test(`edg`) true reg.tes ...

  9. Taro 开发踩坑指南 (小程序,H5, RN)

    Taro 开发踩坑指南 (小程序,H5, RN) css taro 如何展示多行文本省略号 https://www.cnblogs.com/xgqfrms/p/12569057.html UI 设计稿 ...

  10. 小程序 & taro 踩坑指南

    小程序 & taro 踩坑指南 微信开发者工具, 不支持 react bug https://github.com/NervJS/taro/issues/5042 solution just ...

随机推荐

  1. 2021-05-28:跳跃游戏 II。给定一个非负整数数组,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可

    2021-05-28:跳跃游戏 II.给定一个非负整数数组,你最初位于数组的第一个位置.数组中的每个元素代表你在该位置可以跳跃的最大长度.你的目标是使用最少的跳跃次数到达数组的最后一个位置.假设你总是 ...

  2. 【Java】Java代码拷贝文件的速度

    Java代码拷贝文件的速度究竟有多快? 前言 最近学习Java到了流处理,其中有种流叫FileInputStream和FileOutputStream,简单来说,就是操作文件的,老师给我们示范了一个非 ...

  3. SignalR WebSocket通讯机制

    1.什么是SignalR ASP.NET SignalR 是一个面向 ASP.NET 开发人员的库,可简化向应用程序添加实时 Web 功能的过程. 实时 Web 功能是让服务器代码在可用时立即将内容推 ...

  4. docker部署gitlab CI/CD (一)第一篇:部署gitlab及汉化

    网上很多类似教程,但多少有点夹带私货,有的竟然拉取的第三方镜像,而且很多都要修改配置文件,完全不知道是为什么,于是结合其他人的博客和官方文档,知其然也要知其所以然,于2023年4月17日写下这篇. 官 ...

  5. 曲线艺术编程 coding curves 第四章 利萨茹曲线(Lissajous Curves)

    第四章 利萨茹曲线(Lissajous Curves) 原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池 ...

  6. 从源码分析 Go 语言使用 cgo 导致的线程增长

    TDengine Go 连接器 https://github.com/taosdata/driver-go 使用 cgo 调用 taos.so 中的 API,使用过程中发现线程数不断增长,本文从一个 ...

  7. 带你体验AI系列之云原生最佳实践--免费体验GPT-4教程

    前言 ​ [GPT-4]是OpenAI最新推出的大型语言模型,它支持图像和文本输入,以文本形式输出.它比GPT-3.5更大.更强.更猛.最重要的是据与研究表明,他在某些场景下,可以通过图灵测试.但是, ...

  8. String和new String的那点事

    String a= "test"; 此语句含义是:在常量池中创建test字符串对象,变量aa是对常量池中此对象的引用 String aa = new String("te ...

  9. JavaWeb之Servlet详解(以及浏览器调用 Servlet 流程分析图)

    Servlet 1.什么是Servlet Servlet(java 服务器小程序) 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行) 他是用java语言编写的, 本质就是Java类 他是 ...

  10. 手写call&apply&bind

    在这里对call,apply,bind函数进行简单的封装 封装主要思想:给对象一个临时函数来调用,调用完毕后删除该临时函数对应的属性 call函数封装 function pliCall(fn, obj ...