OpenFeign 入门与实战

一、什么是 OpenFeign 

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

Feign 是 Netflix 开源的一个声明式的 Web 服务客户端,它简化了基于HTTP 的服务调用,使得服务间通讯变得更加简单灵活。Feign 通过定义接口、注解和动态代理等方式,将服务调用的过程封装起来,开发者只需要定义服务接口,而无需关心底层的 HTTP 请求和序列化等细节。

OpenFeign vs Feign 的功能升级

  1.  更好的集成 Spring Cloud 组件:OpenFeign 与 Spring Cloud 其他组件(如服务发现,负载均衡等)紧密集成,可以无缝地与其他Spring Cloud 组件一起使用。
  2. 支持 @FeignClient 注解:OpenFeign 引入了 @FeignClient 注解作为 Feign 客户端的标识,可以方便地定义和使用远程服务地声明式接口。
  3. 错误处理改进:OpenFeign 对异常的处理做了增强,提供了更好的错误信息和错误异常处理机制,使得开发者可以更方便地进行错误处理。例如:OpenFeign 提供返回错误响应或请求失败时,OpenFeign 会调用回退策略中的逻辑,提供一个默认的处理结果。
  4. 更丰富的配置项:OpenFeign 提供了丰富的配置选项,可以对 Feign 客户端的行为进行灵活的配置,例如超时设置、重试策略等。

二、OpenFeign 基础使用

OpenFeign 通常要配合注册中心一起使用,并且新版本 OpenFeign 也必须和负载均衡器一起使用,所以它的基础使用步骤如下:

  1. 添加依赖(Nacos 注册中心、OpenFeign、Spring Cloud LoadBalancer)
  2. 配置 Nacos 服务端信息
  3. 在项目中开启 OpenFeign
  4. 编写 OpenFeign 调用代码
  5. 编写代码通过 OpenFeign 调用生产者

具体参考 Nacos-注册中心-CSDN博客

三、超时重传机制

在微服务框架中,服务之间是通过网络进行通信的,而网络是非常复杂和不稳定的,所以在调用服务时可能会失败或超时,那么在这种情况下,我们就需要个 OpenFeign 配置超时重试机制了。

什么时超时重试?

超时重试就是一种在网络通信中常用的策略,用于处理请求在一定时间内未能得到响应或得到超时响应的情况。当发起请求后,如果在规定的时间内没有得到预期的响应,就会触发超时重试机制,重新发送请求。

超时重试的目的主要是提高请求的可靠性和稳定性,以应对网络不稳定、服务不可用、响应延迟等不确定因素。

3.1 配置超时重试 

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

 3.2 覆盖 Retryer

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

四、自定义超时重传机制

自定义重试类

public class MyRetryer implements Retryer {
    private final int maxAttempts;
    private final long period;
    int attempt;

    public MyRetryer(){
        this.maxAttempts=3;
        this.period=1;
        this.attempt=0;
    }

    public MyRetryer(int maxAttempts,long period){
        this.maxAttempts=maxAttempts;
        this.period=period;
        this.attempt=0;
    }



    @Override
    public void continueOrPropagate(RetryableException e) {
        if(attempt++>=maxAttempts){
            throw e;
        }
        long interval=period;
        try {
            //重试间隔时间
            Thread.sleep((interval*(attempt)));
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public Retryer clone() {
        return new MyRetryer(maxAttempts,period);
    }
}

设置配置文件

spring:
  application:
    name: nacos-consumer-demo
  cloud:
    nacos:
      discovery:
        username: nacos
        password: nacos
        server-addr: localhost:8848
        register-enabled: true
    openfeign:
      client:
        config:
          default:            #全局配置
            connect-timeout: 1000 #连接超时时间
            read-timeout: 1000    #读取超时时间
            retryer: com.example.consumer.config.MyRetryer #自定义重试类

server:
  port: 58080

五、超时重试底层实现

5.1 超时重试底层原理

OpenFeign 超时的底层实现是通过配置底层的HTTP 客户端来实现的。OpenFeign 允许你在请求连接和读取数据阶段设置超时时间,具体的超时时间可以通过设置HTTP 客户端的连接超时和读取超时来实现,可以在配置文件中设置超时参数。OpenFeign 底层的HTTP 客户端,可以使用 Apache HttpClient 或 OkHttpClient 来实现,默认使用的是 ApacheClient 实现的。

5.2 重试代码底层实现

通过观察 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();
     // 死循环,如果成功或者重试结束就返回【通过 throw 终止 weile 循环】
     while(true) {
        try {   
             //通过 HTTP Client 发起通信
             return this.executeAndDecode(template, options);
        } catch (RetryableException var9) {
             RetryableException e = var9;
             try {
                // 判断是否重试
                    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 interface Retryer extends Cloneable {
    Retryer NEVER_RETRY = new Retryer() {
        public void continueOrPropagate(RetryableException e) {
            throw e;
        }

        public Retryer clone() {
            return this;
        }
    };

    void continueOrPropagate(RetryableException var1);

    Retryer clone();

    public static class Default implements Retryer {
        private final int maxAttempts;
        private final long period;
        private final long maxPeriod;
        int attempt;
        long sleptForMillis;

        public Default() {
            this(100L, TimeUnit.SECONDS.toMillis(1L), 5);
        }

        public Default(long period, long maxPeriod, int maxAttempts) {
            this.period = period;
            this.maxPeriod = maxPeriod;
            this.maxAttempts = maxAttempts;
            this.attempt = 1;
        }

        protected long currentTimeMillis() {
            return System.currentTimeMillis();
        }

        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;
            }
        }

        long nextMaxInterval() {
            long interval = (long)((double)this.period * Math.pow(1.5, (double)(this.attempt - 1)));
            return interval > this.maxPeriod ? this.maxPeriod : interval;
        }

        public Retryer clone() {
            return new Default(this.period, this.maxPeriod, this.maxAttempts);
        }
    }
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mysql-常用函数及其用法总结

1、字符串函数 测试用例如下&#xff1a; 1.1 CONCAT() 将多个字符串连接成一个字符串。 SELECT CONCAT(first_name, , last_name) AS full_name FROM users; -- 期望结果&#xff1a;John Doe, Jane Smith, Michael Johnson 1.2 SUBSTRING() 提取子字符串 SELECT SUBSTR…

算法012:将x减到0的最小操作数

将x减到0的最小操作数. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/ 这个题使用到的是滑动窗口。 乍一看&#xff0c…

纹波和噪声的介绍以及区别

纹波和噪声的介绍 纹波和噪声都是在电源输出中出现的信号波动&#xff0c;但两者存在明显的区别。   纹波&#xff1a;是附着于直流电平之上的包含周期性与随机性成分的杂波信号。在额定输出电压、电流的情况下&#xff0c;纹波指的是输出电压中的交流电压的峰值 。狭义上的纹…

生产调度:flowshop问题数学建模

接上一篇文章&#xff0c;在了解生产调度问题的背景和基本概念之后&#xff0c;我想先从比较基础的 flowshop和 jobshop 数学模型入手&#xff0c;理解实际调度过程中的问题求解思路。这一篇文章主要面向 flowshop 问题进行数学建模&#xff0c;对于这类比较经典的问题&#xf…

大语言模型基础

大语言基础 GPT : Improving Language Understanding by Generative Pre-Training 提出背景 从原始文本中有效学习的能力对于减轻自然语言处理中对监督学习的依赖至关重要。很多深度学习方法需要大量人工标注的数据&#xff0c;限制了它们在很多领域的应用&#xff0c;收集更…

【鸿蒙学习笔记】MVVM模式

官方文档&#xff1a;MVVM模式 [Q&A] 什么是MVVM ArkUI采取MVVM Model View ViewModel模式。 Model层&#xff1a;存储数据和相关逻辑的模型。View层&#xff1a;在ArkUI中通常是Component装饰组件渲染的UI。ViewModel层&#xff1a;在ArkUI中&#xff0c;ViewModel是…

【Java】垃圾回收学习笔记(二):分代假说与垃圾回收算法

文章目录 0. 分代收集理论分代假说分代GC定义 1. 垃圾回收算法1.1 标记清除&#xff08;Mark-Sweep&#xff09;算法优点缺点 1.2 标记复制算法优点缺点为什么是8:1:1&#xff1f; 1.3 标记整理算法优点缺点 2. 是否移动&#xff1f; 0. 分代收集理论 分代假说 现在多数JVM G…

子数组按位与为k

注意这里的子数组是连续的非空的数组&#xff0c;我们要学会与处理就是求交集 class Solution { public:long long countSubarrays(vector<int>& nums, int k) {long long ans 0;for (int i 0; i < nums.size(); i) {int x nums[i];for (int j i - 1; j > …

MATLAB 2024b 更新了些什么?

MATLAB 2024b版本已经推出了预览版&#xff0c;本期介绍一些MATLAB部分的主要的更新内容。 帮助浏览器被移除 在此前的版本&#xff0c;当我们从MATLAB中访问帮助文档时&#xff0c;默认会通过MATLAB的帮助浏览器&#xff08;Help browser&#xff09;。 2024b版本开始&…

【Linux】压缩命令——gzip,bzip2,xz

1.压缩文件的用途与技术 你是否有过文件太大&#xff0c;导致无法以正常的E-mail方式发送&#xff1f;又或学校、厂商要求使用CD或DVD来做数据归档之用&#xff0c;但是你的单一文件却都比这些传统的一次性存储媒介还要大&#xff0c;那怎么分成多块来刻录&#xff1f;还有&am…

[搭建个人网站] 云服务器 or 本地环境搭建

别人没有的&#xff0c;你有&#xff0c;你就牛。 面试&#xff0c;吹牛皮的时候 都可以拉出来溜溜 本文介绍2种搭建网站模式方式&#xff1a;区别嘛&#xff08;花钱跟不花钱&#xff09; 花钱&#xff1a; 1. 先购买个域名。。&#xff08;这里就不多介绍了&#xff0c;随便…

昇思学习打卡-9-ResNet50图像分类

文章目录 网络介绍数据可视化部分网络实现Building Block结构BottleNet模块 模型训练推理结果可视化学习总结优点不足 网络介绍 在ResNet网络提出之前&#xff0c;传统的卷积神经网络都是将一系列的卷积层和池化层堆叠得到的&#xff0c;但当网络堆叠到一定深度时&#xff0c;…

STM32崩溃问题排查

文章目录 前言1. 问题说明2. STM32&#xff08;Cortex M4内核&#xff09;的寄存器3. 崩溃问题分析3.1 崩溃信息的来源是哪里&#xff1f;3.2 崩溃信息中的每个关键字代表的含义3.3 利用崩溃信息去查找造成崩溃的点3.4 keil5中怎么根据地址找到问题点3.5 keil5上编译时怎么输出…

C++模板元编程(二)——完美转发

完美转发指的是函数模板可以将自己的参数“完美”地转发给内部调用的其它函数。所谓完美&#xff0c;即不仅能准确地转发参数的值&#xff0c;还能保证被转发参数的左、右值属性不变。 文章目录 场景旧的方法新的方法内部实现参考文献 场景 思考下面的代码&#xff1a; templ…

深度学习之网络构建

目标 选择合适的神经网络 卷积神经网络&#xff08;CNN&#xff09;&#xff1a;我们处理图片、视频一般选择CNN 循环神经网络&#xff08;RNN&#xff09;&#xff1a;我们处理时序数据一般选择RNN 超参数的设置 为什么训练的模型的错误率居高不下 如何调测出最优的超参数 …

【pytorch20】多分类问题

网络结构以及示例 该网络的输出不是一层或两层的&#xff0c;而是一个十层的代表有十分类 新建三个线性层&#xff0c;每个线性层都有w和b的tensor 首先输入维度是784&#xff0c;第一个维度是ch_out,第二个维度才是ch_in(由于后面要转置)&#xff0c;没有经过softmax函数和…

C++ 引用——引用的本质

本质&#xff1a;引用的本质在c内部实现是一个指针常量 C推荐用引用技术&#xff0c;因为语法方便&#xff0c;引用本质是指针常量&#xff0c;但是所有的指针操作编译器都帮我们做了 示例&#xff1a; 运行结果&#xff1a;

C++初学者指南-4.诊断---valgrind

C初学者指南-4.诊断—Valgrind Valgrind&#xff08;内存错误检测工具&#xff09; 检测常见运行时错误 读/写释放的内存或不正确的堆栈区域使用未初始化的值不正确的内存释放&#xff0c;如双重释放滥用内存分配函数内存泄漏–非故意的内存消耗通常与程序逻辑缺陷有关&#xf…

水箱高低水位浮球液位开关工作原理

工作原理 水箱高低水位浮球液位开关是一种利用浮球随液位升降来实现液位控制的设备。其基本原理是浮球在液体的浮力作用下上下浮动&#xff0c;通过磁性作用驱动与之相连的磁簧开关的开合&#xff0c;从而实现液位的高低控制和报警。当液位升高时&#xff0c;浮球上浮&#xf…

cmake find_package 使用笔记

目录 1 find_package2 config mode2.1 搜索的文件名2.2 搜索路径 3 module mode3.1 搜索的文件名3.2 搜索路径 参考 1 find_package 这是官方文档 下面是学习总结&#xff1a; 首先是find_package的作用是什么&#xff1f;引入预编译的库。 find_package有两种模式&#xff1a…