思路:Bug探明->源码解读->解决
问题描述与背景
先贴一下完整报错栈:
java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: x.x.x.x
at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:91)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:119)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
at com.sun.proxy.$Proxy199.createTaskGroup(Unknown Source)
at com.finchina.automatic.upgrade.feign.FeignTest.test(FeignTest.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
背景介绍:接到一个需求调用外部Http接口,之前有接触过Feign故想着在这个新项目实战一下,没想到遇到之前没遭遇过的BUG。

如上图,项目POM引入的是OpenFeign,之前用的是Feign。两者的差异其一就是OpenFeign集成了负载均衡的实现,这也是为什么笔者遭遇接下来的BUG。
下面贴图一开始快速搭建,单元测试看Feign是否能调通下游接口的Service。

一开始为了快速调通,所以url直接写死的线下环境,发起Http请求,可以正常收到Response。后面为了实现Url可通过Nacos配置,删除了注解中的Url,在Config类中指定Host的Target。

运行直接报错 java.lang.RuntimeException!

深入排查与原理探明


@FeignClient注解未指定Url时,Url为"", 这里会直接Return;
分为以下几种情况:
1、Url不为空,且Url不包含 #{}时,且Url包含 :// ,则输出为原本Url
2、Url不为空,且Url不包含 #{}时,但Url包含 :// ,则输出为http:// + 原本Url(注意这里如果构成的不是URL,则会抛出异常)
3、Url为空或Url包含 #{}时,直接返回
显然当前的情况为3,接下来继续看为什么返回为空导致Feign负载均衡从而触发去注册中心查找注册的当前服务(服务端并未注册在注册中心,故找不到对应服务,因而报错)。


原来是FeignClientFactoryBean构造这里,当url为空时: 会构造Url为http:// + name, 然后返回了采用loadBalance负债均衡的Client!

顺利成章的,后面在执行的时候,因为Client已经是LoadBalanceFeignClient了,故这里执行的execute接口方法的实现也就是LoadBalanceFeignClient的实现了,如下图:

解决方案
解决方法也很简单,省流方法:随便在@FeignClient注解指定Url,只要不是空值就可以。
![]()
笔者这里就写个EMPTY占位,暂时不想考虑太复杂的改法,等有时间可以深挖一下,应该是可以在构建Client时候手动指定为Default in Client的。
发起调用,看一下是否解决问题:

调上游接口正常返回Response,问题解决!
7899

被折叠的 条评论
为什么被折叠?



