使用Spring Cloud LoadBalancer报错java.lang.IllegalStateException

1 问题描述

在使用Spring Cloud LoadBalancer进行负载均衡时,遇到错误:

而我的代码是这样写的:

java 复制代码
String url = "http://product_service/product/" + orderInfo.getProductId();
ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);

这里使用的restTemplate是使用@LoadBalanced注解的,因此会对该url进行解析,但是解析报错。

2 问题解决

我首先考虑了服务的名称是否正确:

其次输出服务实例的名称,发现输出的名称是大写格式,就把URL服务名称修改为大写,仍然不能解决问题。

然后我怀疑是Spring Cloud内部可能会做字符格式替换之类的,进行了如下几组实验,目前的三种情况如下:

|-----------------|-----------------|------|
| yml文件服务名称 | URL服务名称 | 实验结果 |
| product_service | product-service | 报错 |
| product-service | product-service | 不报错 |
| product_service | product_service | 报错 |
| product-service | product_service | 报错 |

URL中为短横线格式时,就不会报错。而第1组实验报错是因为实例名称不匹配,对于第3组实验报错,因此推测可能是LoadBalancer不能解析下划线:

查阅资料发现,LoadBalancer解析时强制不能使用下划线,需要使用短横线进行单词连接。这是由于LoadBalancer的源码中核心是LoadBalancerInterceptor类,它会把所有的请求都拦截,并进行解析,在该类的intercept方法中使用getHost()获取URL中的主机名(也就是服务实例名称):

java 复制代码
    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }

在getHost()方法内部已经标注了主机名的命名规范:

即只接受-作为连字符来连接标签,如果不符合规范就返回为null。因此使用product_service作为URL中服务实例名称就无法解析。

修改后,问题得到解决。建议URL和yml中使用的服务名称如果要用连字符,都要用短横线连接的规范形式。

相关推荐
Boilermaker19921 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
Cherry的跨界思维1 小时前
28、AI测试环境搭建与全栈工具实战:从本地到云平台的完整指南
java·人工智能·vue3·ai测试·ai全栈·测试全栈·ai测试全栈
alonewolf_992 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
一嘴一个橘子2 小时前
spring-aop 的 基础使用(啥是增强类、切点、切面)- 2
java
sheji34162 小时前
【开题答辩全过程】以 中医药文化科普系统为例,包含答辩的问题和答案
java
恋爱绝缘体13 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
xiaolyuh1233 小时前
Spring 框架 核心架构设计 深度详解
spring·设计模式·spring 设计模式
wszy18093 小时前
新文章标签:让用户一眼发现最新内容
java·python·harmonyos
wszy18093 小时前
顶部标题栏的设计与实现:让用户知道自己在哪
java·python·react native·harmonyos
程序员小假4 小时前
我们来说一下无锁队列 Disruptor 的原理
java·后端