- 前言
- 组件版本
- 具体内容
- 问题描述
- 解决过程
- 通过写死ip地址(域名也可)实现,示例
- 通过从 eureka 获取 ip地址,示例
- 这两个方法的入口地址
- 造成实现不同的原因
- 总结
springcloud => Finchley.SR2版本 spring-cloud-starter-openfeign => 2.0.2.RELEASE spring-cloud-starter-netflix-eureka-client => 2.0.2.RELEASE具体内容
问题描述我这里feign是通过从eureka注册中心获取对应服务的ip地址,然后执行远程服务调用
解决过程 通过写死ip地址(域名也可)实现,示例通过方面的方法执行调用时,由于远程服务执行的逻辑较多(处理时长大约2-4s),导致调用者报错,异常信息为
Read timed out executing GET http://FEIGN-INTERFACE/feign/linkByEureka
但是我本地debug的时候,由于偷懒,没有走eureka注册中心,而是直接写了ip地址。然后看它底层实现的时候,发现它的默认值是
字段介绍参考
connectTimeoutMills=10000 //建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用时间
readTimeoutMills=60000 // 指的是建立连接后从服务器读取到可用资源所需的时间,即发送请求到接收到结果的时间
且在这种情况下,我执行调用时为出现前面的错误(我本地模拟的话是直接线程睡眠3s)。
这进一步让我感到困惑,之后我想到有情况对默认值的覆盖情况,但是我测试的仍是写死ip地址,导致迟迟没发现问题。
之后我在查询资料,看到了这里的超时介绍
想到了是否是其他框架对它的实现造成了影响,最后发现是eureka的问题。
@FeignClient(name = "test",url = "http://localhost:8088")
public interface TestFeign {
@RequestMapping("/get")
String get();
}
这种情况下它执行调用的时候是Client.Default.execute(request,options)方法
@FeignClient(name = "FEIGN-INTERFACE")
public interface FeignTest {
@RequestMapping("/feign/linkByEureka")
String linkByEureka();
}
这种情况下它执行的是LoadBalancerFeignClient.execute(request,options)方法
入口地址为 SynchronousMethodHandler.executeAndDecode(template),源码第88行。
造成实现不同的原因org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget()方法 源码239行
总结T getTarget() { FeignContext context = applicationContext.getBean(FeignContext.class); Feign.Builder builder = feign(context); // 通过注册中心这里进去 if (!StringUtils.hasText(this.url)) { String url; if (!this.name.startsWith("http")) { url = "http://" + this.name; } else { url = this.name; } url += cleanPath(); return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type, this.name, url)); } if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { this.url = "http://" + this.url; } // 直接写死ip地址,则跳过前面两个if,这里开始执行逻辑 String url = this.url + cleanPath(); Client client = getOptional(context, Client.class); //这个方法两者都会调用,最终获得一个LoadBalancerFeignClient if (client != null) { // 这里会将 LoadBalancerFeignClient 变回 Client.Default类,从而导致之后采用不同的实现。 if (client instanceof LoadBalancerFeignClient) { // not load balancing because we have a url, // but ribbon is on the classpath, so unwrap client = ((LoadBalancerFeignClient)client).getDelegate(); } builder.client(client); } Targeter targeter = get(context, Targeter.class); return (T) targeter.target(this, builder, context, new HardCodedTarget<>( this.type, this.name, url)); }
// 使用feign 最好 定义超时时间 feign.client.config.default.connect-timeout=2000 // 默认连接超时时间 feign.client.config.default.read-timeout=3000 // 默认读取超时时间 feign.client.config.FEIGN-INTERFACE.connect-timeout=2000 // 某个feign 的时间,用的name字段,区分大小写。 feign.client.config.FEIGN-INTERFACE.read-timeout=3000 // 某个feign 的时间,用的name字段,区分大小写。
2.0.2.RELEASE 版本好像还有个bug,两个时间要同时指定,不然无效。



