OpenFeign的简单介绍和功能实操

news2024/10/7 14:32:10

前言

本文主要做一下OpenFeign的简单介绍和功能实操,实操主要是OpenFeign的超时和重试,在阅读本文章前,请完成《Nacos 注册中心介绍与实操》内的Nacos多模块生产消费者项目

什么是OpenFeign

OpenFeign全名Spring Cloud OpenFeign,是SpringCloud开发团队基于Feign开发的框架,声明式Web服务客户端

  • Feign是一种声明式、模板化的HTTP客户端,可用于调用HTTP API实现微服务之间的远程服务调用。它的特点是使用少量的配置定义服务客户端接口,可以实现简单和可重用的RPC调用。
  • Feign实现了声明式调用,允许程序员只需定义接口并作出一些小的注释,就可以实现一个完整的客户端,从而开发简单,潜在的问题可以被检测出来,程序的可维护性和可读性也更好。
  • Feign支持动态服务发现,可以在接口地址变更或服务重新发布后实现自动切换,避免了因配置变更导致的杂乱代码,更具有拓展性。
  • Feign解决了服务之间依赖过于厚实的一种解决方案,相比REST或RPC,Feign可以减少大量不必要的代码。它基于可插拔修改的过滤链,默认支持多种HTTP请求和响应。

OpenFeign功能升级

OpenFeign在Feign的基础上提供了增强和扩展功能:
1、更好的集成SpringCloud其他组件:可以和服务发现、负载均衡组件一起使用
2、支持@FeignClient注解:OpenFeign引入该注解作为Feign客户端标识,可以方便地定义和使用远程服务调用
3、错误处理改进:OpenFeign对异常进行了增强,提供了更好的错误信息和异常处理机制,让开发者更为准备的判断错误所在。

如:OpenFeign提供的错误解码器(DefaultErrorDecoder)和回退策略(当服务端返回错误响应或请求失败时,OpenFeign会调用回退策略中的逻辑,提供一个默认的处理结果)。

4、更丰富的配置项:可以对Feign客户端进行配置,如超时时间、重传次数等


OpenFeign客户端

客户端与服务端的代码创建请前往Nacos 注册中心介绍与实操这篇文章上参考完成。

① 要使用OpenFeign需要使用@EnableFeignClients进行开启

@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

② 编写接口服务,并使用@FeginClient(name=“xxxx”)来指定调用的服务站点

@Service
@FeignClient(name = "nacos-provider")
public interface UserService {

    @RequestMapping("/user/getInfo")
    public String getInfo(@RequestParam("name") String name);
}

③ 调用接口

@RestController
public class OrderController {

    private final UserService userService;

    @Autowired
    public OrderController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping("/order")
    public String getInfo(){
        if(userService == null){
            return null;
        }
        return userService.getInfo(" Spring Cloud");
    }
}

④ 最终结果
在这里插入图片描述


OpenFeign中的超时重试机制

众所周知,在这个机器交互过程中,网络是最为复杂和难以控制的,而我们的微服务,讲究的就是一个高并发高可用,那么解决交互上存在的网络问题是十分必要的。

那么在OpenFeign中采用的方式就是超时重传,和TCP协议中的超时重传机制一样,链接或者消息在一定时间没有回应就会重新发送一次。

其实这很容易理解,就像我们在平时打电话,你沟通时,过一会对面都没有回应,你也会“喂,喂,听得见吗?”的消息确认。


开启超时重传机制

OpenFeign在默认情况下是不会开启这个机制的,需要我们人为去开启,那么开启需要通过下面两个步骤

  1. 配置超时重传
  2. 覆盖Retryer对象

1、配置

spring:
	cloud:
	    openfeign:
      		client:
       			config:
          			default: # 全局配置
            			connect-timeout: 1000 # ms 链接超时时间
            			read-timeout: 1000 # ms 读取超时时间

2、覆盖

在消费者目录下的config包下构建并注入IOC容器

@Configuration
public class RetryerConfig {

    @Bean
    public  Retryer retryer(){
        return new Retryer.Default(
                1000,        // 重试间隔时间
                1000,        // 最大间隔时间
                3            // 最大重试次数
        );
    }
}

为了演示超时重传的触发,我们在生产者代码上使用Thread.sleep(2000)来让线程睡眠并且在进打印调用的时刻,这个睡眠时间超过配置中的read-time=1000

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/getInfo")
    public String getInfo(@RequestParam("name") String name){
        System.out.println("provider.getInfo方法执行时间:"+ LocalDateTime.now());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "producer" + name;
    }
}

生产者控制台信息:
在这里插入图片描述

客户端结果:
在这里插入图片描述


下面我们队这个结果进行一个简单的分析:
在consumer.getInfo()对provider.getInfo(“Spring Cloud”)进行调用的时候,由于provider.getInfo(“Spring Cloud”)中进行了睡眠,并且(sleep=2000ms) > (read-time=1000ms),所以引发了超时现象


超时后,由于我们设置了超时重试次数,那么OpenFeign将会按照这个Retryer中的规则进行重试,再次调用了provider.getInfo(“Spring Cloud”)方法,再次打印了方法执行时间


在重试了一定次数后,我们的consumer.getInfo()都收不到回应,那么就会导致客户端获取信息失败,然后就报了500错误,任务是服务端出错了。


以上就是超时重传的简单实操,不过需要做一点简单的补充,可能有同学已经发现了,provider控制台打印的时间上有点和想象中的不一样
在这里插入图片描述
这里我们可以看到重试是两秒左右才进行的,而我们connect-time = 1000ms ||read-time=1000ms,都不为一秒啊,为什么是两秒才调用,而不是一秒呢????

如果有以上问题的同学,应该是忘记了Retryer中的一个参数,重试间隔时间=1000ms,这就以为则,如果我们出现了超时问题,具体重传的时间还需要加上重试间隔时间,才是真正调用服务的时间:(connect-time > 1000 || read-time > 1000)+ (period = 1000) == executetime


自定义超时重试机制

无敌的Spring Cloud肯定也思考到了灵活性,所以也提供了自定义超时重试机制的方式,分为下面两个步骤:

  1. 自定义超时重试机制(实现Retryer接口,重写continueOrPropagate);
  2. 设置配置文件

三种自定义超时重试类

  1. 固定时间间隔:也就是说,每次重试开始时间间隔一样,例如:上面的实操例子
  2. 增长性间隔:例如:第一次超时重试间隔1秒,第二次2秒,第三次3秒,具体如何增长看业务实现的增长函数
  3. 随机时间间隔:重试间隔在一定范围内随机

自定义超时类实操

说明 :这个实操基于第一种自定义超时类来实现,不需要注入IOC

1、自定义超时重试机制

public class MyRetryConfig implements Retryer {
    private final int maxAttempts;  // 最大尝试次数
    private final long intervalTime;// 重试间隔时间

    private int attempt;            // 当前尝试次数

    public MyRetryConfig() {
        this.maxAttempts = 3;
        this.intervalTime = 1000;
        this.attempt = 0;
    }

    public MyRetryConfig(int maxAttempts, long intervalTime) {
        this.maxAttempts = 3;
        this.intervalTime = 1000;
        this.attempt = 0;
    }
    @Override
    public void continueOrPropagate(RetryableException e) {
        // 假如当前尝试次数超过了最大尝试次数就抛出异常
        if(++this.attempt > this.maxAttempts){
            throw e;
        }
        long curInterval = this.intervalTime;
        // 打印日志
        System.out.println(LocalDateTime.now() + "执行了一次重试");
        try {
            Thread.sleep(curInterval);
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * 克隆(创建独立的实例)
     * @return
     */
    @Override
    public Retryer clone() {
        // 克隆的间隔时间和重试次数当然要和被克隆对象一直,所以有参构造更为正确
        return new MyRetryConfig(maxAttempts, intervalTime);
    }
}

2、将自定义超时重传类声明到yml配置文件中

关键词:retryer: com.example.consumer.config.MyRetryConfig

spring:
  application:
    # 服务注册站点
    name: nacos-consumer #命名不能使用‘_’,早期SpringCloud不支持
  cloud:
    nacos:
      # Nacos认证信息
      discovery:
        username: nacos
        password: nacos
        # Nacos 服务发现与注册配置,其中子属性server-addr指定Nacos服务器主机和端口
        server-addr: localhost:8848
        namespace: public # 注册到nacos的指定namespace,默认public
        register-enabled: false
    openfeign:
      client:
        config:
          default: # 全局配置
            connect-timeout: 1000 # ms 链接超时时间
            read-timeout: 1000 # ms 读取超时时间
            retryer: com.example.consumer.config.MyRetryConfig
server:
  port: 8080

测试结果:

超时重试底层原理

超时原理

超时原理其实很简单,OpenFeign超时底层实现是通过配置HTTP客户端来实现,通过你对配置文件的connect-timeout和read-timeout来底层进行设置

OpenFeign底层的HTTP客户端可以使用Apache HttpClient或者OK HttpClient来实现,默认是ApacheHttpClient

重试原理

通过观察OpenFeign 的源码实现就可以了解重试功能的底层实现,它的源码在 SynchronousMethodHandler 的 invoke 方法下,如下所示

**public Object invoke(Object[] argv) throws Throwable {
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Request.Options options = this.findOptions(argv);
        Retryer retryer = this.retryer.clone();
		// 一直重试
        while(true) {
            try {
            	// 如果得到结果就return退出循环
                return this.executeAndDecode(template, options);
            } catch (RetryableException var9) {
                RetryableException e = var9;

                try {
                	// 如果遇到异常则调用Retryer的continueOrPropagate
                    retryer.continueOrPropagate(e);
                } catch (RetryableException var8) {
                    Throwable cause = var8.getCause();
                    if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
                        throw cause;
                    }

                    throw var8;
                }

                if (this.logLevel != Level.NONE) {
                    this.logger.logRetry(this.metadata.configKey(), this.logLevel);
                }
            }
        }
    }

Retryer的continueOrPropagate方法底层实现:

public void continueOrPropagate(RetryableException e) {
            if (this.attempt++ >= this.maxAttempts) {
                throw e;
            } else {
                long interval;
                if (e.retryAfter() != null) {
                    interval = e.retryAfter().getTime() - this.currentTimeMillis();
                    if (interval > this.maxPeriod) {
                        interval = this.maxPeriod;
                    }

                    if (interval < 0L) {
                        return;
                    }
                } else {
                    interval = this.nextMaxInterval();
                }

                try {
                    Thread.sleep(interval);
                } catch (InterruptedException var5) {
                    Thread.currentThread().interrupt();
                    throw e;
                }

                this.sleptForMillis += interval;
            }
        }

补充说明

OpenFeign实现原理
1.注解
2.动态代理实现—>功能扩展
3.RestTemplate发送HTTP请求
4.HTTP框架来实现Web请求->Apache HttpClient或者OK HttpClient


END
希望对你有帮助

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

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

相关文章

基础课16——客服中心内部使用的智能客服系统

客服中心内部使用的智能客服系统主要包括以下几类&#xff1a; 智能客服机器人(呼入、呼出)&#xff1a;可以自动回答用户的问题&#xff0c;并能根据用户需求进行多轮对话。它采用了先进的自然语言处理技术&#xff0c;能理解并回答用户的问题&#xff0c;并根据需要自主分析…

Redis入门03-多线程和有序集合

目录 Redis的多线程 Redis有序集合的集合操作 Redis的多线程 Redis6.0版本推出了多线程&#xff0c;需要注意的是Redis6.0的多线程是⽤多线程来处理数据的读写和协议解析&#xff0c;但是Redis执⾏命令还是单线程的。官方FAQ表示&#xff0c;因为Redis是基于内存的操作&…

python:pybullet 3D游戏物理引擎 安装过程

先从 Microsoft C Build Tools - Visual Studio 下载 1.73GB 安装 "Microsoft C Build Tools“ 现在&#xff0c;我们将创建一个虚拟环境&#xff0c;并在其中安装 numpy , pybullet cd /python python -m venv myenv cd myenv 使用 Scripts\activate 激活环境&…

【C/C++】积累和派生类的转换

基类与派生类对象之间有赋值兼容关系&#xff0c;由于派生类中包含从基类继承的成员&#xff0c;因此可以将派生类的值赋给基类对象&#xff0c;在用到基类对象的时候可以用其子类对象代替。具体表现在以下几个方面。 一、派生类对象可以向基类对象赋值 可以用子类(即公用派生…

11、电路综合-集总参数电路结构的S参数模型计算与Matlab

11、电路综合-集总参数电路结构的S参数模型 电路综合专栏的大纲如下&#xff1a; 网络综合和简化实频理论学习概述 前面介绍了许多微带线电路综合的实际案例&#xff0c;如&#xff1a; 3、电路综合原理与实践—单双端口理想微带线&#xff08;伪&#xff09;手算S参数与时域…

vue-advanced-chat使用指南

demo地址:https://gitee.com/beekim/vue-advanced-chat vue-advanced-chat的git地址:https://github.com/advanced-chat/vue-advanced-chat 1.搭建demo demo地址克隆后在demo目录安装依赖并启动 启动之后的页面如下: 2.前端代码分析 2.1 重点api分析 current-user-id:…

使用PyQuery库构建有趣的爬虫程序

目录 一、爬虫程序概述 二、PyQuery库介绍 三、使用PyQuery编写爬虫程序 四、注意事项和潜在问题 五、总结 本文将介绍如何使用PyQuery库编写一个有趣且实用的爬虫程序。我们将首先简要介绍爬虫程序的概念和应用&#xff0c;然后详细探讨PyQuery库的特点和优势。接着&…

符号执行初识

一、符号执行概念 符号执行&#xff08;Symbolic Execution&#xff09;是一种程序分析技术&#xff0c;它 可以通过分析程序来得到让特定代码区域执行的输入。 符号执行的 目的 是在给定的时间内&#xff0c; 生成一组输入&#xff0c;并通过这些输入尽可能多的探索执行路径。…

动作捕捉系统进行坐标系转换

动作捕捉系统在机器人等应用中常出现被测物与动捕坐标系不一致的问题。这时就需要进行坐标系的转换。在NOKOV度量动作捕捉系统软件中&#xff0c;可以对被测物的坐标系原点偏移量进行设置&#xff0c;实现被测物坐标系与大地坐标系的重合。 一、坐标系偏移操作 在形影动捕软件…

【数据结构】单向链表的增删查改以及指定pos位置的插入删除

目录 单向链表的概念及结构 尾插 头插 尾删 ​编辑 头删 查找 在pos位置前插 在pos位置后插 删除pos位置 删除pos的后一个位置 总结 代码 单向链表的概念及结构 概念&#xff1a;链表是一种 物理存储结构上非连续 、非顺序的存储结构&#xff0c;数据元素的 逻辑顺序 是…

代码随想录第四十一天 | 动态规划:整数拆分(343,加贪心);不同的二叉搜索树(96)

1、leetcode 343&#xff1a;整数拆分 1.1 leetcode 343&#xff1a;动态规划 第一遍代码没思路 代码随想录思路 看到这道题目&#xff0c;都会想拆成两个呢&#xff0c;还是三个呢&#xff0c;还是四个… 我们来看一下如何使用动规来解决 动规五部曲&#xff0c;分析如下&…

win10 + vs2017 + gdal2.0.3 编译

1. 下载并解压gdal2.0.3 我的放置目录是&#xff1a;D:\Depend_3rd_party\gdal2\gdal-2.0.3&#xff0c;其中gdal-2.0.3是解压得到的文件夹 2. 修改 nmake.opt 文件 用notepad打开nmake.opt文件&#xff0c;修改以下三个部分&#xff1a; &#xff08;1&#xff09;修改C co…

【Java 进阶篇】深入了解 Java ServletContext

Java ServletContext是Java Servlet技术中的一个重要概念&#xff0c;它提供了一种在整个Web应用程序中共享数据和资源的方式。在本文中&#xff0c;我们将深入探讨ServletContext的用途、工作原理和示例用法。无需担心&#xff0c;即使您是一个基础小白&#xff0c;也可以轻松…

C++:string类!

Cstring 是C中的字符串。 字符串对象是一种特殊类型的容器&#xff0c;专门设计来操作的字符序列。 不像传统的c-strings,只是在数组中的一个字符序列&#xff0c;我们称之为字符数组&#xff0c;而C字符串对象属于一个类&#xff0c;这个类有很多内置的特点&#xff0c;在操作…

首届陕西省商贸服务业“金牌店长”大赛落下帷幕

2023年11月1日&#xff0c;首届陕西省商贸服务业金牌店长大赛在秋林大酒店落下帷幕。这是由陕西省商业联合会、陕西省餐饮联合会、陕西省连锁经营协会和西安市连锁经营协会联合举办&#xff0c;旨在挖掘和培养陕西省商贸服务业的优秀店长&#xff0c;提升商贸服务业的整体水平&…

Java多线程----创建线程、线程池ExecutorService、异步编排

文章目录 创建线程的四种方式方式一、继承Thread方式二、自定义实现Runnable接口方式三、Thread FutureTask Callable返回值方式四、线程池ThreadPoolExecutor 线程池的简单介绍通过ThreadPoolExecutor创建自定义线程池ThreadPoolExecutor创建线程池的7大参数线程池处理任务的…

在校园跑腿系统小程序中,如何设计高效的实时通知与消息推送系统?

1. 选择合适的消息推送服务 在校园跑腿系统小程序中&#xff0c;选择一个适合的消息推送服务。例如&#xff0c;使用WebSocket技术、Firebase Cloud Messaging (FCM)、或第三方推送服务如Pusher或OneSignal等。注册并获取相关的API密钥或访问令牌。 2. 集成服务到小程序后端…

(1)上位机底部栏 UI如何设置

上位机如果像设置个多页面切换&#xff1a; 位置&#xff1a; 代码如下&#xff1a; "tabBar": {"color": "black","selectedColor": "#d43c33","borderStyle":"black","backgroundColor": …

数据库 | 看这一篇就够了!最全MySQL数据库知识框架!

大家好&#xff01; 作为一名程序员&#xff0c;每天和各种各样的“数据库”打交道&#xff0c;已经成为我们的日常。当然&#xff0c;立志成为一名超级架构师的我&#xff0c;肯定要精通这项技能。咳咳&#xff01;不过饭还是要一口一口吃的&#xff0c;“数据库”这个内容实在…

黄执中老师人际说服课思考总结(个人笔记整理 ①)

问题描述和解决方法&#xff1a; &#x1f624;职场中明明是ta应该做的事&#xff0c;ta为何还生气呢&#xff1f;&#xff1b; &#x1f620;不知道怎么和家人孩子沟通&#xff1f;自己明明是对的&#xff0c;可别人就是不听 &#x1f621;不知道怎么安慰朋友&#xff1f;&…