提供 Eureka Client 服务的应用名是: eureka-client
Ribbon + Eureka 使用的时候,通过 RestTemplate
会刨除以下错误:
2021-03-08 11:31:10.214 ERROR 26501 --- [nio-8781-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.Illeg
alStateException: No instances available for eureka-client] with root cause
java.lang.IllegalStateException: No instances available for eureka-client
at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:119) ~[spring-cloud-netflix-ribbon-2.2.7.RELEASE.jar:2.2.7.RELEASE]
at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:99) ~[spring-cloud-netflix-ribbon-2.2.7.RELEASE.jar:2.2.7.RELEASE]
at org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor.intercept(LoadBalancerInterceptor.java:56) ~[spring-cloud-commons-3.0.1.jar:3.0.1]
at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:77) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) ~[spring-web-5.3.4.jar:5.3.4]
找了很久, 非常头疼, 网上找的的文章 核对过无数次,并没有发现自己少做什么, 但是问题依然无法解决, 于是只能自己动手解决了。
经过尝试后, 发现:
如果使用的是 spring-cloud-starter-ribbon
没有太大的问题, 但是 spring-cloud-starter-ribbon
已经作废了。 eureka, eureka-server 也是类似的。
Spring Cloud Starter Ribbon
Spring Cloud Starter Ribbon (deprecated, please use spring-cloud-starter-netflix-ribbon)
改用了 spring-cloud-starter-netflix-ribbon
以后, loadBalancerClient.choose("eureka-client")
是 null, 并没有获取已经注册的 eureka-client。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>LATEST</version>
</dependency>
restTemplate.getForObject
被调用的时候, 就会出现以上错误(原因和上面一样, 是 RibbonLoadBalancerClient.choose() = null):
但是 discoveryClient.getInstances("eureka-client")
是可以获取到注册的 Eureka 服务的.
解决方法一
在 RibbonEurekaClientConfig
中添加代码后就可以了:
@Bean
public ServerList<Server> getServerList(IClientConfig config) {
return new ServerList<Server>() {
@Override
public List<Server> getInitialListOfServers() {
return new ArrayList<>();
}
@Override
public List<Server> getUpdatedListOfServers() {
List<Server> serverList = new ArrayList<>();
List<ServiceInstance> list = discoveryClient.getInstances(config.getClientName());
for (ServiceInstance instance : list) {
serverList.add(new Server(instance.getHost(), instance.getPort()));
}
return serverList;
}
};
}
原因是因为没有获取到已经注册的 eureka-client 的服务。 添加以下代码, 在初始化 ServerList<Server>
的时候, 会使用自己实现的 getUpdatedListOfServers()
方法
解决方法二
通过读源码,找到了关键的地方
DynamicServerListLoadBalancer.initWithNiwsConfig()
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
try {
super.initWithNiwsConfig(clientConfig);
String niwsServerListClassName = clientConfig.getPropertyAsString(
CommonClientConfigKey.NIWSServerListClassName,
DefaultClientConfigImpl.DEFAULT_SEVER_LIST_CLASS);
ServerList<T> niwsServerListImpl = (ServerList<T>) ClientFactory
.instantiateInstanceWithClientConfig(niwsServerListClassName, clientConfig);
this.serverListImpl = niwsServerListImpl;
...
关键的地方是 serverListImpl
, 默认的是 com.netflix.loadbalancer.ConfigurationBasedServerList
, 这个类获取的是配置中的 listOfServers
(不用 Eureka的场景).
initWithNiwsConfig() --> restOfInit() --> updateListOfServers()
com.netflix.loadbalancer.ConfigurationBasedServerList
是通过配置 IClientConfig
中的 NIWSServerListClassName
的值反射而来的, 通过在 application.yml
中配置可以改变:
ribbon:
NIWSServerListClassName: com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
这个类是包 ribbon-eureka
中的类. 在 pom.xml
中引入:
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-eureka</artifactId>
<version>2.3.0</version>
</dependency>
这里的版本需要注意一下, spring-cloud-starter-netflix-ribbon
中的 ribbon-core
的版本是 2.3.0
, 所以这里的版本就是 2.3.0
. 这里的版本不一致可能会导致错误。
这时在 RibbonEurekaClientConfig.java
中只修改方法 getServerList
:
@Bean
public ServerList<Server> getServerList(IClientConfig config) {
DynamicServerListLoadBalancer<Server> serverDynamicServerListLoadBalancer = new DynamicServerListLoadBalancer<>();
serverDynamicServerListLoadBalancer.initWithNiwsConfig(config);
return serverDynamicServerListLoadBalancer.getServerListImpl();
}
注意这里主要修改的文件有 3 个:
- pom.xml
- application.yml
- RibbonEurekaClientConfig.java