Open Feign

news2024/11/29 22:29:54

Open Feign

在前面的学习中,我们使用了Ribbon的负载均衡功能,简化了远程调用时的代码:

String user = this.restTemplate.getForObject("http://spring-provider/provider/" + id, String.class);

如果就学到这里,可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。有没有更优雅的方式,来对这些代码再次优化呢?这就是我们接下来要学的Feign的功能了。

简介

Netflix 提供了 Feign,并在 2016.7 月的最后一个版本 8.18.0 之后,将其捐赠给 spring cloud 社区,并更名为 OpenFeign 。OpenFeign 的第一个版本就是 9.0.0 ,OpenFeign 会完全代理 HTTP 的请求,在使用过程中我们只需要依赖注入 Bean,然后调用对应的方法传递参数即可。这对程序员而言屏蔽了 HTTP 的请求响应过程,让代码更趋近于『调用』的形式。

Feign是一个远程调用组件,集成了ribbon和hystrix。把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。

在这里插入图片描述

入门

导入依赖

1、引入依赖

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

2、启动类增加@EnableFeignClients

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 开启feign客户端,无需配置熔断器和负载均衡注解
public class SpringConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringConsumerApplication.class, args);
    }
}

启动类增加了新的注解: @EnableFeignClients,如果我们要使用 Feign(声明式 HTTP 客户端),必须要在启动类加入这个注解开启 Feign 。

这样,我们的 Feign 就已经集成完成了,那么如何通过 Feign 去调用之前我们写的 HTTP 接口呢?

首先创建一个接口 ApiService(名字任意),并且通过注解配置要调用的服务地址。

Feign的客户端

@FeignClient(value = "spring-provider") // 标注该类是一个feign接口
public interface ProviderOpenfeign {

    @GetMapping("/sms/provider/{id}")
    String provider(@PathVariable("id") String id);
}
  • 这是一个接口,Feign会通过动态代理,帮我们生成实现类。这点跟mybatis的mapper很像;
  • @FeignClient,声明这是一个Feign客户端,类似@Mapper注解。同时通过value属性指定服务名称;
  • 接口中定义的方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果;
  • 一个服务只能被一个类绑定,不能让多个类绑定同一个远程服务,否则,会在启动项目是出现『已绑定』异常。

说明:

1、方法的返回值、参数以及requestmapping路径要和提供方的一模一样和消费方无关,消费方只需要调用该方法得到结果;
2、如果服务方controller类有@RequestMapping 定义命名空间,provider,在这里我们建议在方法上面拼接,不能在ProviderOpenfeign接口上去定义@requestMapping("/provider/");
3、@PathVariable("id") 这个括号里面的id不能省略,同理@Requestparam("id")里面的id也不能省略。

改造原来的调用逻辑,调用ProviderOpenfeign接口:

@Controller
public class ConsumerController {

    @Autowired
    private ProviderOpenfeign providerOpenfeign;

	@RequestMapping("/consumerOpenfeign/{id}")
    public String consumerOpenfeign(@RequestParam("id") String id){
        String consumer = providerOpenfeign.provider(id);
        return "consumerOpenfeign " + consumer;
    }
}

Hystrix支持

OPen Feign默认也有对Hystrix的集成:

在这里插入图片描述

默认是关闭的,我们需要通过下面的参数来开启:

feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能,默认超时1s

只需要开启hystrix的熔断功能即可,默认时间是1s中,如果要修改熔断的时间,要做如下的配置:

feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能
  client:
    config:
      default:
        connectTimeout: 4000  #设置feign超时连接时长
        readTimeout: 4000  #设置feign请求的超时时长  4s之后 提供方没有响应 直接降级
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000  
          strategy: THREAD
        timeout:
          enabled: true

说明:

connectTimeout是feign连接某个服务的超时时间,

readTimeout是feign请求某个接口的超时时长,

timeoutInMilliseconds是hystrix熔断的时间,

Hystrix的超时时间是站在命令执行时间来看的和Feign设置的超时时间在设置上并没有关联关系。Hystrix不仅仅可以封装Http调用,还可以封装任意的代码执行片段。Hystrix是从命令对象的角度去定义,某个命令执行的超时时间,超过此此时间,命令将会直接熔断,假设hystrix 的默认超时时间设置了3000(3秒),而feign 设置的是4秒,那么Hystrix会在3秒到来时直接熔断返回,不会等到feign的4秒执行结束,如果hystrix的超时时间设置为6s,而feign 设置的是4秒,那么最终要以feign的时间4s为准,你可以理解为以时间短的为准,这两段都要配置,不能不配hystrix的配置,否则feign配置的readTimeout不生效。

Feign中的Fallback降级配置不像hystrix中那样了。

1)首先,我们要定义一个类ProviderOpenfeignFallback,实现刚才编写的ProviderOpenfeign,作为fallback的处理类

@Component
public class ProviderOpenfeignFallback implements ProviderOpenfeign {

    @Override
    public User provider(String id) {
        return "服务器繁忙,请稍后再试!";
    }
}

2)然后在ProviderOpenfeign中,指定刚才编写的实现类

@FeignClient(value = "spring-provider",fallback = ProviderOpenfeignFallback.class) // 标注该类是一个feign接口
public interface ProviderOpenfeign {

    @GetMapping("/provider/{id}")
    String provider(@PathVariable("id") String id);
}

3)修改消费方controller的consumerOpenfeign方法,注释掉**@HystrixCommand注解和@DefaultProperties(defaultFallback=“fallback”)**进行测试。

@RestController
//@DefaultProperties(defaultFallback = "fallbackMethod")
public class ConsumerController {
    @Autowired
    private ProviderOpenfeign providerOpenfeign;

    @RequestMapping(value = "/consumerOpenfeign/{id}")
	//@HystrixCommand
    public String consumerOpenfeign(@PathVariable String id){
        String consumer = providerOpenfeign.provider(id);
        return "consumerOpenfeign consumer " + consumer;
    }
}

4)重启测试:

在这里插入图片描述

超时和超时重试

OpenFeign 本身也具备重试能力,在早期的 Spring Cloud 中,OpenFeign 使用的是 feign.Retryer.Default#Default() ,重试 5 次。但 OpenFeign 集成了Ribbon依赖和自动配置(默认也是轮询),Ribbon 也有重试的能力,此时,就可能会导致行为的混乱。(总重试次数 = OpenFeign 重试次数 x Ribbon 的重试次数,这是一个笛卡尔积。)

后来 Spring Cloud 意识到了此问题,因此做了改进(issues 467),将 OpenFeign 的重试改为 feign.Retryer#NEVER_RETRY ,即默认关闭。 Ribbon的重试机制默认配置为0,也就是默认是去除重试机制的,如果两者都开启重试,先执行ribbon重试,抛出异常之后再执行feign的重试。

所以,OpenFeign『对外』表现出的超时和重试的行为,实际上是 Ribbon 的超时和超时重试行为。我们在项目中进行的配置,也都是配置 Ribbon 的超时和超时重试

在调用方配置如下

# 全局配置
ribbon:
  # 请求连接的超时时间
  connectTimeout: 1000
  # 请求处理的超时时间
  readTimeout: 1000   #1秒
  # 最大重试次数
  MaxAutoRetries: 5
  # 切换实例的重试次数
  MaxAutoRetriesNextServer: 1
  #NFLoadBalancerRuleClassName: RandomRule
  # 对所有请求开启重试,并非只有get 请求才充实。一般不会开启这个功能。该参数和上面的3三个参数没有关系
  #okToRetryOnAllOperations: true
feign:
  hystrix:
    enabled: true     #默认是1s降级
  #client:         
    #config:
     # default:
       # connectTimeout: 4000  #要关掉feign超时连接时长
        #readTimeout: 150000
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 100000   #这个时间要大于ribbon重试次数的总时长,否则还没重试完就降级了

被调用方设置线程睡眠

@RestController
public class ProviderController {

    @Value("${server.port}")
    private String port;

    @RequestMapping(value = "/provider/{id}")
    public String provider(@PathVariable String id){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            return "exception:" + e.getMessage();
        }
        return "provider id = " + id + "port = " + port;
    }
}

测试结果:由于openfeign重试默认是关闭的,我们不用管它。被调用方,如果只启动一个被调方实例,则一共12次,因为 MaxAutoRetriesNextServer: 1 切换下一个实例再重试,下一个实例还是自己,如果被调方启动两个实例,则各6次。另外重试和熔断都开启,超时时间是1s,一共是12次,也就是12s,12s之后就会降级,而hystrix配置的timeoutInMilliseconds的15s降级,在这里是以时间短的为主。如果不对timeoutInMilliseconds进行配置,那么hystrix默认是1s,也就是1s钟之后就会降级,但是不影响ribbon的重试。

你也可以指定对某个特定服务的超时和超时重试:

则其他的请求走上面的重试,spring-provider该服务的重试单独配置

# 针对 spring-provide 的设置,注意服务名是小写
spring-provide:
  ribbon:
    connectTimeout: 1000
    readTimeout: 3000   
    MaxAutoRetries: 2
    MaxAutoRetriesNextServer: 2

在被调方,修改如下代码测试

@RestController
public class ProviderController {

    @Value("${server.port}")
    private String port;

    @RequestMapping(value = "/provider/{id}")
    public String provider(@PathVariable String id){
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            return "exception:" + e.getMessage();
        }
        return "provider id = " + id + "port = " + port;
    }
}

替换底层用HTTP实现

本质上是 OpenFeign 所使用的 RestTemplate 替换底层 HTTP 实现

  • 替换成 HTTPClient

将 OpenFeign 的底层 HTTP 客户端替换成 HTTPClient 需要 2 步:

1、引入依赖:

<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-httpclient</artifactId>
 </dependency>

2、在配置文件中启用它:

feign:
  httpclient:
    enabled: true # 激活 httpclient 的使用
  • 替换成 OkHttp

将 OpenFeign 的底层 HTTP 客户端替换成 OkHttp 需要 2 步:

1、引入依赖

<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>

2、配置

feign:
  httpclient:
    enabled: false  # 关闭 httpclient 的使用
  okhttp:
    enabled: true   # 激活 okhttp 的使用

日志级别(了解)

前面讲过,通过logging.level.xx=debug来设置日志级别。然而这个对Fegin客户端而言不会产生效果。因为@FeignClient注解修改的客户端在被代理时,都会创建一个新的Fegin.Logger实例。我们需要额外指定这个日志的级别才可以。然后根据 logging.level. 参数配置格式来开启 Feign 客户端的 DEBUG 日志,其中 部分为 Feign 客户端定义接口的完整路径。默认值是NONE,而NONE不会记录Feign调用过程的任何日志的,也就是说这个日志不是启动feign客户端的日志,而是feign调用远程接口时产生的日志

1)设置com.woniu包下的日志级别都为debug

logging:
  level:
    com:
      woniu:
        openfeign:
          ProviderOpenfeign: debug   #ProviderOpenfeign为某个feign接口

2)编写配置类,定义日志级别

内容:

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

这里指定的Level级别是FULL,Feign支持4种级别:

在这里插入图片描述

  • NONE:不记录任何日志信息,这是默认值。
  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

3)在FeignClient中指定配置类:

@FeignClient(value = "spring-provider",fallback = ProviderOpenfeignFallback.class, configuration = FeignLogConfiguration.class)
public interface ProviderOpenfeign {

    @GetMapping("/provider/{id}")
    String provider(@PathVariable("id") String id);
}

4)重启项目,进行测试:在通过openfeign去调用某个接口时,会有详细的信息。如果把日志级别设置为NONE,则没有。

测试:http://localhost:8280/consumerOpenfeign

ml
logging:
level:
com:
woniu:
openfeign:
ProviderOpenfeign: debug #ProviderOpenfeign为某个feign接口


2)编写配置类,定义日志级别

内容:

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

这里指定的Level级别是FULL,Feign支持4种级别:

[外链图片转存中...(img-IP80Hi1k-1694490245931)]

- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

3)在FeignClient中指定配置类:

```java
@FeignClient(value = "spring-provider",fallback = ProviderOpenfeignFallback.class, configuration = FeignLogConfiguration.class)
public interface ProviderOpenfeign {

    @GetMapping("/provider/{id}")
    String provider(@PathVariable("id") String id);
}
```

4)重启项目,进行测试:在通过openfeign去调用某个接口时,会有详细的信息。如果把日志级别设置为NONE,则没有。

测试:http://localhost:8280/consumerOpenfeign 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1007971.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Zebec 生态 AMA 回顾:Nautilus 以及 $ZBC 的未来

在 9 月 7 日&#xff0c;Zebec 创始人 Sam 做客社区&#xff0c;并进行了“Nautilus Chain 以及 $ZBC 的未来”主题的 AMA 访谈。Sam 在本次访谈中对 Nautilus Chain 生态的价值捕获、Zebec 生态布局规划、可能会推出的 Nautilus Chain 治理通证 NAUT 进行了解读。本文将对本次…

基于SSM的医院在线挂号预约系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

人大女王金融硕士项目——应以长远的眼光去规划自己的人生蓝图

我们的现在的生活都是过去努力的结果&#xff0c;你的未来如何是由今后的努力决定。我们不要停滞不前&#xff0c;应从长远的眼光去规划自己的人生蓝图。你有想过在职攻读人民大学与加拿大女王大学金融硕士项目来提升自己吗&#xff1f; 着我国经济迅猛的发展&#xff0c;金融…

鸿蒙HarmonyOS应用开发初体验

最近华为发布mt60新机火了&#xff0c;作为一名移动开发程序员&#xff0c;对鸿蒙系统开发移动端就很感兴趣了。 开发工具&#xff1a;HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 下载完后按默认安装就可以了&#xff0c;界面跟AS很类似&#xff0c;之前我jdk环…

前端面试合集(二)

前端面试题合集 1.懒加载的原理及实现了解吗2.如何理解JS异步3.阐述一下 JS 的事件循环4.JS 中的计时器能做到精确计时吗&#xff1f;为什么&#xff1f; 1.懒加载的原理及实现了解吗 原理&#xff1a;当图片没有到达可视范围内时&#xff0c;图片不加载&#xff0c;当图片一旦…

【Realtek sdk-3.4.14b】RTL8197FH-VG和RTL8812F自适应认证失败问题分析及修改

WiFi自适应认证介绍 WiFi 自适应可以理解为针对WiFi的产品,当有外部干扰信号通过,WiFi产品自动停止发出信号一段时间,以达到避让的目的。 问题描述 2.4G和5G WiFi自适应认证失败,信道停止发送信号时间过长,没有在规定时间内停止发包 2.4G截图 问题分析 根据实验室描述可以…

yolov7简化网络yaml配置文件

yolov7代码结构简单&#xff0c;效果还好&#xff0c;但是动辄超过70几个模块的配置文件对于想要对网络进行魔改的朋友还是不怎么友好的&#xff0c;使用最小的tiny也有77个模块 代码的整体结构简单&#xff0c;直接将ELAN结构化写成一个类就能像yolov5一样仅仅只有20几个模块&…

[H5动画制作系列] 奔跑的豹子的四种Demo演化

资源: bg.jpg: leopard.png: 背景透明 peopard2.png 背景不透明 参考代码1: leopard.js: (function(window) {ma = function() {this.initialize();}ma._SpriteSheet = new createjs.SpriteSheet({images: ["leopard.png"], frames: [[0,0,484,207],[486,0,484,20…

H5唤醒App

H5唤醒App 在App的业务场景中&#xff0c;H5唤醒App是一个几乎必备的功能。比如你想要实现以下需求&#xff1a;当App内容通过各种途径&#xff08;短信、二维码、微信等&#xff09;触达用户&#xff0c;从浏览器或者第三方内部可以直接打开H5网页&#xff0c;由网页端交互操作…

线性代数的本质(十)——矩阵分解

文章目录 矩阵分解LU分解QR分解特征值分解奇异值分解奇异值分解矩阵的基本子空间奇异值分解的性质矩阵的外积展开式 矩阵分解 矩阵的因式分解是把矩阵表示为多个矩阵的乘积&#xff0c;这种结构更便于理解和计算。 LU分解 设 A A A 是 m n m\times n mn 矩阵&#xff0c;…

web安全漏洞-SQL注入实验2

实验目的 学习sql显注的漏洞判断原理掌握sqlmap工具的使用分析SQL注入漏洞的成因 实验工具 sqlmapsqlmap是用python写的开源的测试框架&#xff0c;支持MySQL&#xff0c;Oracle&#xff0c;PostgreSQL&#xff0c;Microsoft SQL Server&#xff0c;Microsoft Access&#x…

SLS 1508 支持艾默生DeltaV报警抑制模块的设计

SLS 1508 支持艾默生DeltaV报警抑制模块的设计 宣布其SILAlarm V2.10合理化工具支持艾默生DeltaV报警抑制模块的设计和自动配置。这些模块通过在满足预定义条件时抑制来自操作员的警报来消除警报泛滥&#xff0c;并帮助用户符合ISA-18.2和IEC 62682标准。 报警抑制逻辑在艾默…

安全测试BurpSuite-抓包篡改数据

bp做安全测试很核心的一个步骤就是抓包 一、配置代理 浏览器代理&#xff0c;第一种使用浏览器自身手动代理 第二种下载插件&#xff08;推荐使用&#xff0c;切换多个代理方便&#xff09; 1、浏览器chrome/火狐安装插件 2、配置对应的代理情景 二、burp suite配置对应的…

List与ArrayList

目录 一、List及其使用 1.1 List的概念 1.2 常见接口的介绍 1.3 List的使用 二、线性表和顺序表 2.1 线性表 2.2 顺序表 三、ArrayList介绍 四、ArrayList的使用 4.1 ArrayList构造 4.2 ArrayList的常用方法 4.3 ArrayList的遍历 4.4 ArrayList的扩容机制 五、ArrayList的具…

LVS负载均衡群集NAT模式

LVS负载均衡群集NAT模式 一、集群与分布式1.1、集群的含义1.2、lvs模型1.3、系统性能扩展方式1.4、群集的三种类型1.4.1、负载均衡群集1.4.2、高可用群集1.4.3、高性能运算群集 1.5、LVS的负载调度算法1.5.1、轮询1.5.2、加权轮询1.5.3、最少连接1.5.4、加权最少连接1.5.5、ip_…

【Spring源码解析】一文读懂Spring注入模型:开发者必备知识

文章目录 什么是注入模型注入模型的种类案例分析例子一创建Bean对象创建配置类重写后置处理器创建测试类执行测试方法分析 例子二改写站点类&#xff0c;去掉Autowired注解重写后置处理器执行测试方法分析思考 ✨这里是第七人格的博客✨小七&#xff0c;欢迎您的到来~✨ &#…

华为云云耀云服务器L实例评测|怎么搭建企业综合Web平台

前言 记得2019年&#xff0c;公司搞混合云的时候&#xff0c;测试过多家公有云&#xff0c;其中就有华为云。因公司也在深圳&#xff0c;项目也比较急&#xff0c;我司业务上云经验又不足&#xff0c;华为官方获悉情况后&#xff0c;第二天就派了4人小团队到我司来交流&#x…

金蝶云星空与金蝶云星空对接集成发货通知单查询打通发货通知单新增

金蝶云星空与金蝶云星空对接集成发货通知单查询打通发货通知单新增 数据源平台:金蝶云星空 金蝶K/3Cloud结合当今先进管理理论和数十万家国内客户最佳应用实践&#xff0c;面向事业部制、多地点、多工厂等运营协同与管控型企业及集团公司&#xff0c;提供一个通用的ERP服务平台…

加载动态库失败(loadLibrary返回为空 GetLastError126)解决办法 dll有依赖的dll缺失

问题&#xff1a;加载动态库失败&#xff08;loadLibrary返回为空&#xff09; 排除&#xff1a;64位也对。平台相同。 错误&#xff1a;至少找不到一个必需的隐式或转发依赖项。这个不影响。 SmartPay_PGL.dll下的四个dll&#xff0c;则是他所依赖的四个dll。因为我这里有缺失…

破天荒呀!小杜微信有名额了

写在前面 小杜粉&#xff0c;众所周知前面加小杜微信为好友的基本都是由名额限制的。一般都是付费进入社群且进行备注&#xff0c;小杜才会长期保留微信好友。主要由于&#xff0c;添加的人数太多了&#xff0c;微信账号人数名额有限。因此&#xff0c;小杜过一段时间&#xf…