springcloud => Finchley.SR2版本
spring-cloud-starter-openfeign => 2.0.2.RELEASE
spring-cloud-starter-netflix-eureka-client => 2.0.2.RELEASE
我这里feign是通过从eureka注册中心获取对应服务的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,两个时间要同时指定,不然无效。