首页>资讯 > 综合资讯 > 正文

Feign如何设置超时时间,不同情况下还真不一样

来源:三友的java日记    2023-08-15 10:23:20

大家好,我是三友~~

今天来聊一聊前段时间看到的一个面试题,也是在实际项目中需要考虑的一个问题,Feign的超时时间如何设置?

Feign的超时时间设置方式并不固定,它取决于Feign在项目中是如何使用的,不同的使用方式,超时时间设置方式也不大相同,甚至还可能有坑。


(资料图片)

前置知识

由于文章会涉及到Feign的底层知识,如果不懂点Feign的基本概念的话,后面就看不下去了

所以为了方便不了解Feign的小伙伴也能够读得懂文章,这里我就简单地说说Feign的原理,点到为止,虽然不深入,但足够应付这篇文章了

Feign的作用

在项目中,我们经常需要调用第三方提供的Http接口,此时我们就可以使用一些Http框架来实现,比如HttpClient

public class HttpClientDemo {    public static void main(String[] args) throws Exception {        //创建一个HttpClient        HttpClient httpClient = HttpClientBuilder.create().build();        //构建一个get请求        HttpGet httpGet = new HttpGet("http://192.168.100.1:8080/order/1");        //发送请求,获取响应        HttpResponse httpResponse = httpClient.execute(httpGet);        HttpEntity httpEntity = httpResponse.getEntity();        //读出响应值        String response = EntityUtils.toString(httpEntity);        System.out.println("Response: " + response);    }}

如果项目中只有一两个这种第三方接口这样写还行,但是一旦这种三方接口过多的话,每次都得这样组装参数,发送请求,写一堆同样的代码,就显然很麻烦了。

所以为了简化发送Http请求的开发,减少重复代码,Feign就出现了。

Feign是一个声明式的Http框架

当你需要调用Http接口时,你需要声明一个接口,加一些注解就可以了

而像组装参数、发送Http请求等重复性的工作都交给Feign来完成。

Feign的原理

虽然有了接口,但是仅仅有接口是不够的,因为接口又不能创建对象,我们得需要对象。

Feign为了方便我们为接口创建对象,提供的Feign.Builder这个内部类

图片

这个类的作用就是解析接口的上的注解,为接口生成一个动态代理对象,后面通过这个代理对象就可以发送请求了。

这个内部类有很多属性,这些属性都是Feign的核心组件。

在这些核心的组件中有一个叫Client的,上图中我圈出来了。

图片

这个Client类划个重点,非常非常重要,本文讨论的东西跟他有密切关系。

它只有一个方法Response execute(Request request, Options options)

方法的第一个参数Request就是封装了http请求的url、请求方法,请求头、请求体之类的参数

图片

第二个参数Options就是本文的主题,封装了超时时间。

图片

返回值Response就是封装了一些响应码status、响应头之类的

图片

所以通过方法的参数和返回值也可以猜出来,这个Client作用是用来组装Http请求参数,发送Http请求的

并且http请求超时时间是根据传给Client的Options参数来决定的

图片

如果想更深一步了解Feign原理,可在公众号菜单栏springcloud分类中查看

Feign单独使用时超时时间设置

Feign本身就是一个http客户端,可独立使用,Feign提供了两种超时时间设置方式

1、通过Feign.Builder设置

前面提到,Feign.Builder的作用是为接口的动态代理对象的

Feign.Builder里面有很多属性,其中就有关于超时时间的属性Options

图片

如果你不设置,那么超时时间就是默认的

图片

默认的就是连接超时10s,读超时60s

所以可以通过设置Feign.Builder中的options来设置超时时间

来个demo

环境准备,就是一个简单的SpringBoot项目,引入一个Feign的依赖

            org.springframework.cloud        spring-cloud-starter-openfeign        2.2.5.RELEASE    

声明接口 + 注解

public interface UserApi {    @RequestLine("GET /user/{userId}")    User queryUser(@Param("userId") Integer userId);}

这里演示的是Feign原生的使用方式,脱离于SpringCloud环境,所以Spring的那些@GetMappring就不支持了,改用Feign本身提供的注解

测试代码

public class FeignDemo {    public static void main(String[] args) {        UserApi client = Feign.builder()                //设置连接和读超时间都是5s                .options(new Request.Options(5, TimeUnit.SECONDS, 5, TimeUnit.SECONDS, true))                .target(UserApi.class, "http://localhost:8088");        User user = client.queryUser(123);    }}

这里面的请求路径都是不存在的,因为我们只关心传给Client的Options参数值

Client在我们不设置的时候,就用默认的实现Client.Default

图片

断点打到execute方法的实现,运行,走起

图片

结果就是我们设置的5s

2、在接口方法参数设置

除了在通过Feign.Builder时设置之外,Feign还支持在接口的方法参数上设置

此时你只需要在接口的方法上加一个Options类型的参数

@RequestLine("GET /user/{userId}")User queryUser(@Param("userId") Integer userId, Request.Options options);

这样在传参数时就可以设置超时时间了

User user = client.queryUser(123, new Request.Options(3, TimeUnit.SECONDS, 3, TimeUnit.SECONDS, true));

同样地,debug就可以看见我们设置的3s了

图片

这两种设置超时时间的主要区别就是方法参数设置超时时间的优先级高于Feign.Builder设置的超时时间

用一张图来总结一下上面的关系

图片

所以,如果你单独使用Feign的时候,你就可以通过如上的两种方式来设置超时时间。

SpringCloud下Feign单独使用超时时间设置

在SpringCloud环境下,只是对Feign进行了一层包装,所以即使没有Ribbon和注册中心,Feign也是可以单独使用的,但是用法有点变化

注解都换成SpringMVC的注解接口上需要加@FeignClient注解用@EnableFeignClients扫描这些接口

不过,默认情况下Feign还是需要结合Ribbon来使用的

如果你只想单独使用Feign,那么就设置一下@FeignClient注解的url属性,指定请求的地址和端口就可以了

图片

所以,既然只是包装,前面提到的两种方式设置超时时间当然可以继续使用:

通过Feign.Builder通过接口的方法参数

方法参数设置形式跟前面提到的一模一样,但是通过Feign.Builder来设置却不太一样

由于SpringCloud会自己创建Feign.Builder,不需要我们创建,所以在设置Options时,Spring提供了两种快捷方式来设置

不过最终还是设置到Feign.Builder中

1、声明一个Options Bean

Spring在构建Feign.Builder的时,会从容器中查找Options这个Bean,然后设置到Feign.Builder中

@Configurationpublic class FeignConfiguration {    @Bean    public Request.Options options() {        return new Request.Options(8, TimeUnit.SECONDS, 8, TimeUnit.SECONDS, true);    }}

此时debug就可以看到设置到Feign.Builder的代码

图片

这段代码在FeignClientFactoryBean中的configureUsingConfiguration方法中

2、配置文件中设置

除了声明Bean之外,Spring还提供了通过配置文件的方式配置,如下:

feign:  client:    config:      default:        connectTimeout: 10000        readTimeout: 10000

同样地,debug就可以看见

图片

这段代码在FeignClientFactoryBean中的configureUsingConfiguration方法中

声明Bean和配置文件都可以设置,那么同时设置哪种优先级高呢?

如无特殊配置,遵守SpringBoot本身的配置规定

约定 > 配置 > 编码

所以基于这个规定,配置文件的配置优先级大于手动声明Bean的优先级。

到这,我们又学到了两种Spring为了方便我们设置Feign.Builder提供的配置方式:

声明Options Bean配置文件

把他们俩加到前面画的图中

图片

所以,如果你使用了SpringCloud提供的方式来使用Feign,那么就可以通过声明OptionsBean和配置文件的方式更加方便地来设置超时时间

最终其实还是通过Feign.Builder来设置的

SpringCloud下通过Ribbon来设置

当Feign配合Ribbon使用时,除了上面两种方式之外,还可以通过Ribbon来设置超时时间。

但是这里我不知道你会不会好奇

Ribbon不是负载均衡组件,怎么可以设置超时时间?

其实这跟Ribbon的定位有关,除了负载均衡组件之外,Ribbon也干发送Http请求的事,也就是不配合Feign,他照样可以发送http请求。

来个简单demo

图片

解释一下上面的代码意思

第一步,设置user服务的两个服务实例地址第二步,获取user服务对应的RestClient,这RestClient就可以用来发送http请求第三步,构建一个http请求第四步,就是发送http请求,以负载均衡的方式

这样,此时就会从两个服务实例中根据负载均衡选取一个服务地址发送http请求,

Ribbon既然可以发送Http请求,那么自然而然就可以设置超时时间

Feign在整合Ribbon的时候,为了统一配置,就默认将自己的超时时间交由Ribbon管理

所以,在默认情况下,Feign的超时时间可以由Ribbon配置

而Ribbon默认连接和读超时时间只有1s,所以在默认情况下,Feign的超时时间只有1s。

图片

IClientConfig是Ribbon的配置类,Ribbon所有的配置都可以从IClientConfig中获取。

所以,在默认情况下,很容易就发生超时,不过我们可以通过配置文件修改即可

ribbon:  ConnectTimeout: 5000  ReadTimeout: 5000

你知道你发现没,上面说通过Ribbon设置Feign的超时时间,一直提到前面一直提到这个词

默认

什么情况下叫默认呢?

所谓的默认,就是当你不主动设置Feign的超时时间的时候,就是默认。

换句话说,一旦你通过上面说的那些配置方式设置Feign的超时时间,就不是默认了

此时通过Ribbon设置的超时时间就不会生效了

Feign是如何在默认情况下将超时时间交给Ribbon管理的?

要想回答这个问题,就得先搬出前面反复提到的Client接口了。

在SpringCloud的环境下,有一个Client的实现,叫LoadBalancerFeignClient

图片

通过名字就可以看出,带有负载均衡的Client实现,负载均衡的实现肯定是交给Ribbon来实现的

所以当Feign配合Ribbon时用的就是这个Client实现

既然实现了Client接口,那就看看execute方法的实现逻辑

图片

图中getClientConfig方法就是判断使用Feign或者Ribbon配置的核心逻辑

核心的判断逻辑就是这一行

options == DEFAULT_OPTIONS

DEFAULT_OPTIONS就是一个超时时间的常量

图片

当上述判断条件成立时,就会通过this.clientFactory.getClientConfig(clientName)获取到Ribbon配置

由于这是Ribbon的逻辑,这里就不深扒了,知道是这个意思就行

当条件不成立时,用Options构建一个FeignOptionsClientConfig

图片

FeignOptionsClientConfig就是简单地将Options配置读出来,设置到父类DefaultClientConfigImpl超时时间配置上

DefaultClientConfigImpl就算你不知道是什么也无所谓,你能看出的一件事就是,超时时间用的是传递给Client的Options参数

所以,综上,我们的问题就变得非常easy了,那就是什么时候

options == DEFAULT_OPTIONS

只有当这个条件成立时,才使用Ribbon的配置。

这里我们先来捋一捋前面提到的东西

前面我们反复提到,Client的Options最终只来自于两种配置

Feign.Builder方法参数

所以DEFAULT_OPTIONS这个Options一定是通过上面两种方法中的其中一种设置的

而方法参数是不可能设置的成DEFAULT_OPTIONS

因为这是我们控制的,只要我们参数不传DEFAULT_OPTIONS,那么永远都不可能是DEFAULT_OPTIONS。

此时只剩下一种情况,那就是Spring在构建在Feign.Builder的时候,设置成DEFAULT_OPTIONS。

通过查找DEFAULT_OPTIONS的使用,我们可以追踪到这么一段代码

图片

这不就是前面提到的通过声明Bean的方式来设置超时时间

不同的是它加了@ConditionalOnMissingBean,这个注解就是说,一旦我们自己没有声明Options,就用他这个Options

到这终于真像大白了。

我们不设置超时时间,Spring就会给Feign.Builder加一个DEFAULT_OPTIONS这个Options

在执行的时候,发现是DEFAULT_OPTIONS,说明我们没有主动设置过超是时间,就会使用Ribbon的超时时间。

为了方便理清上面的逻辑,这里整一张图

图片

虽然Feign可以使用Ribbon的超时时间,但是Ribbon的配置的优先级是最最低的

方法参数 > Feign配置文件 > 声明Options > Ribbon配置

Feign or Ribbon配置用哪个好?

其实我个人更倾向于使用Ribbon的配置方式。

因为Ribbon除了可以设置超时时间之外,还可以配置重试机制、负载均衡等其它的配置

为了简化和统一管理配置,使用Ribbon来配置超时时间。

可能你会有疑问,Feign也支持重试机制,为什么不选择Feign?

这是因为Feign重试机制没有Ribbon的好

Ribbon重试的时候会换一个服务实例来重试,因为原来出错的可能不可用

而Feign并不会换一个服务实例重试,他并不知道上一次使用的是哪个服务实例,这就导致可能会出现在一个不可用的服务实例上多次重试的情况。

引入Hystrix时超时时间设置

如果你之前的确没有研究过关于Feign超时时间的配置关系,那么此时你应该有所收获了。

但是这就结束了么?

不,事情没那么简单。

如果你的项目中使用了Hystrix,那么就得小心前面说的那些配置了。

由于Hystrix跟Feign毕竟是一家人,所以当引入Hystrix时,Feign就跟之前不一样了。

Hystrix会去干一件事,那就是给每个Feign的http接口保护起来,毕竟Hystrix就是干保镖这个事的。

但是这没保护还好,一保护问题就不自觉地出现了。

Hystrix在保护的时候,一旦发现被保护的接口执行的时间超过Hystrix设置的最大时间,就直接进行降级操作。

怎么降级的,这里咱不关心,咱关心的是这个Hystrix超时的最大值是多少。

因为一旦这个时间小于Feign的超时时间,那么就会出现Http接口正在执行,也没有异常,仅仅是因为执行时间长,就被降级了。

而Hystrix的默认的超时时间的最大值就只有1s。

图片

所以就算你Feign超时时间设置的再大,超过1s就算超时,然后被降级,太坑了。。

所以我们需要修改这个默认的超时时间的最大值,具体的配置项如下

hystrix:  command:    default:      execution:        isolation:          thread:            timeoutInMilliseconds: 30000

并且时间上大致要符合下面这个原则

Hystrix超时时间 >= (连接超时时间 + 读超时时间) * 重试次数

重试次数我们前面也提到了,虽然一般我们不设置,但是为了严谨还是得加上,因为一次Http接口的执行时间肯定跟重试次数有关,重试次数越多,时间就越长。

而连接超时时间 + 读超时时间设置方式,前面提到很多次,不论是通过Feign本身设置还是通过Ribbon来设置,都是可以的

总结

今天给大家扒了扒在不同使用条件下Feign的超时时间设置,总结起来大致如下:

单独使用Feign时:通过Feign.Builder和方法参数SpringCloud环境下单独使用Feign:方法参数、配置文件、声明OptionsBean跟Ribbon配合使用:通过Ribbon的超时参数设置跟Hystrix配合使用:修改默认的超时时间,尽量符合 Hystrix超时时间 >= (连接超时时间 + 读超时时间) * 重试次数

关键词:

Feign如何设置超时时间,不同情况下还真不一样

大家好,我是三友~~今天来聊一聊前段时间看到的一个面试题,也是在实际

玉米价格再创年内新高

新华财经北京8月15日电进入8月份,玉米价格持续上涨,中旬再创年内新高

浙南地区最大天然气保供工程——浙能温州LNG接收站进入试运行阶段

浙南地区最大天然气保供工程——浙能温州LNG接收站进入试运行阶段近日

苹果m3主机什么时候出

很多用户都非常的关注苹果最新发布的M3处理器,也有消息称这个处理器将

碳酸锂:2023Q2海外锂资源供给更新

澳大利亚2023年二季度,澳大利亚Greenbush、Pilbara、MtCattlin、Finni

央行8月22日将在香港招标发行3个月期200亿元和1年期150亿元人民币央票

证券时报网讯,央行网站消息,为丰富香港高信用等级人民币金融产品,完

解开混乱:探索电子竞技锦标赛瑞士回合形式的奥秘

LPL结束了所有的比赛,即将进入新一阶段的备战集训。与此同时,LCK仍在

克苏恩之眼能换什么 克苏恩之眼换什么

1、堕落神明咒符堕落神明咒符拾取后绑定颈部+11耐力需要等级60装备:提

武清区 36个村转移安置人员已回迁

天津北方网讯:从武清区防汛抗旱指挥部获悉,截至8月14日,武清区大黄

昆明举办食源性疾病防控与救治工作培训班

昆明信息港讯(昆明日报记者徐婕)近日,由昆明市卫生健康委主办、昆明

浙江东日:8月14日融券卖出100股,融资融券余额1.98亿元

8月14日,浙江东日(600113)融资买入37 17万元,融资偿还98 97万元,

淘宝怎么看自己的评价?(淘宝怎么看自己的评价)

小评来为大家解答以上问题。淘宝怎么看自己的评价?,淘宝怎么看自己的

8月17日沈阳有无人机矩阵表演,这些路段将实行交通管制

“第十届沈阳法库国际飞行大会航空主题嘉年华活动(无人机矩阵表演)”

安德利08月14日获沪股通增持4.33万股

08月14日,安德利获沪股通增持4 33万股,最新持股量为36 92万股,占公

深圳、广州和佛山是广东省GDP总量前三位城市,都位于珠三角地区

广东省位于我国南部沿海地区,广东省地处南岭以南,南濒南海,与广西、

口子窖:8月14日融券卖出金额143.53万元,占当日流出金额的0.91%

同花顺数据中心显示,口子窖8月14日获融资买入883 11万元,占当日买入

笔记本任务管理器在哪里(笔记本任务管理器)

小评来为大家解答以上问题。笔记本任务管理器在哪里,笔记本任务管理器

沈阳现代化都市圈养老服务一体化合作协议签署

记者8月14日获悉,为加快推进沈阳现代化都市圈养老服务发展建设,促进

俄罗斯秋明州发生一起交通事故 已致5死2伤

据俄新社报道,当地时间8月15日凌晨,俄罗斯秋明州发生一起交通事故,

磷是什么(磷是什么元素)

磷是第15号化学元素,符号P。处于元素周期表的第三周期、第ⅤA族。磷存

《不完美受害人》:不完美才显真实

《不完美受害人》:不完美才显真实

沈阳本周天气以多云为主 偶有阵雨

末伏啦!夏天大部分难捱的日子算是过去了,但处暑节气还没到,我们不能

木工开孔器哪家好 木工开孔器生产厂家盘点 木工开孔器最常用的型号

大家知道什么是木工开孔器吗?木工开孔器是一种在制作木工的时候使用的

红星美凯龙(01528):潘宁、巢艳萍退任职工代表监事

智通财经APP讯,红星美凯龙(01528)发布公告,唐荣镇及王守义于公司2023

69年属鸡今年运势2021年运势(69年属鸡的今年的运气)

来为大家解答以上的问题。69年属鸡今年运势2021年运势,69年属鸡的今年

辽宁全力以赴打好打赢防汛防台风这场硬仗

防汛防台风是一场大战、一场大考。全省各地各相关部门牢固树立“防大汛

征求意见!沈阳或将出台这些政策措施 助力恢复和扩大消费

今年新能源汽车充电终端保有量达到3万个;多子女家庭可足额提取公积金

手机突然充电超级慢是不是电池问题(手机突然充电超级慢)

诸多的对于手机突然充电超级慢是不是电池问题,手机突然充电超级慢这个

大陆刚宣布对台反制,国民党要员就喊话柯文哲,不许大陆企业中标

大陆刚宣布对台反制,国民党要员就喊话柯文哲,不许大陆企业中标,大陆,

媒体:A股也可以考虑取消印花税 基本情况讲解

大家好,今日关于【媒体:A股也可以考虑取消印花税】迅速上了的热搜榜

综合资讯

+更多

热点资讯

+更多
股票当天买入可以当天再卖出吗?初学者怎么炒股?
股票当天买入可以当天再卖出吗?1、 当天买入的内资股当天不能卖出,只能在下一个交易日卖出,卖出股票的钱当天不能支取,只能在下一个交易 [详细]

Copyright @ 2008-2020  www.43710.com   All Right Reserved Powered by 财经情报网 版权所有

财经情报网   联系邮箱:562 66 29@qq.com

网站备案:沪ICP备2020036824号-12