不知道從哪一個版本起(目測跟版本無關,應該是ribbon.eureka.enabled=true的狀況下
),給ribbon配置物理的server list起,單純配置xxx.ribbon.listOfServers不起效果了,因而就開啓了埋坑之旅。java
目前使用的是Camden.SR6版本web
java.lang.IllegalStateException: No instances available for xxx at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:75) at org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor.intercept(LoadBalancerInterceptor.java:53) at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:86) at org.springframework.cloud.netflix.metrics.MetricsClientHttpRequestInterceptor.intercept(MetricsClientHttpRequestInterceptor.java:68) at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:86) at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:70) at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613) at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:407) at org.springframework.web.client.RestTemplate$$FastClassBySpringCGLIB$$aa4e9ed0.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) at org.springframework.cloud.netflix.metrics.RestTemplateUrlTemplateCapturingAspect.captureUrlTemplate(RestTemplateUrlTemplateCapturingAspect.java:33) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) at org.springframework.web.client.RestTemplate$$EnhancerBySpringCGLIB$$ec1f757d.postForEntity(<generated>)
當時是把外部的服務名改了致使的
)致使使用到了錯誤的server list。spring
@RibbonClient(name = "xxx",configuration = XxxRibbonConfig.class) public class XxxRibbonConfig { String listOfServers = "http://192.168.99.100:8080,http://192.168.99.101:8080"; @Bean public ServerList<Server> ribbonServerList() { List<Server> list = Lists.newArrayList(); if (!Strings.isNullOrEmpty(listOfServers)) { for (String s: listOfServers.split(",")) { list.add(new Server(s.trim())); } } return new StaticServerList<Server>(list); } }
這個的問題是把這個配置放到了@ComponentScan掃描的包下面post
查看/beansthis
{ "bean": "ribbonServerList", "aliases": [], "scope": "singleton", "type": "org.springframework.cloud.netflix.ribbon.StaticServerList", "resource": "class path resource [com/xxx/XxxRibbonConfig.class]", "dependencies": [] }
會發現多個ribbonClient的話,其中一個的ribbonServerList註冊爲全局的了。(爲何會註冊爲全局的?
)而spring-cloud-netflix-core-1.2.6.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.javaurl
@Bean @ConditionalOnMissingBean @SuppressWarnings("unchecked") public ServerList<Server> ribbonServerList(IClientConfig config) { if (this.propertiesFactory.isSet(ServerList.class, name)) { return this.propertiesFactory.get(ServerList.class, config, name); } ConfigurationBasedServerList serverList = new ConfigurationBasedServerList(); serverList.initWithNiwsConfig(config); return serverList; }
這裏發現已經有了ribbonServerList,並且沒有找到指定的服務名的server list配置,因而就採用了全局的。.net
解決方案很簡單,就是修改成正確的服務名就能夠了。另一個方案就是不使用RibbonClient配置,最簡單的就是配置文件添加NIWSServerListClassName屬性:rest
xxx: ribbon: ReadTimeout: 60000 ConnectTimeout: 60000 NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList listOfServers: http://192.168.99.100:8080,http://192.168.99.101:8080
在不使用NIWSServerListClassName屬性配置,使用RibbonClient配置的前提下,如何規避全局ribbonServerList呢?code
@SpringCloudApplication @RibbonClients(value = { @RibbonClient(name = "xxx",configuration = XxxRibbonConfig.class), @RibbonClient(name = "demo",configuration = DemoRibbonConfig.class) }) public class DemoServiceApplication { public static void main(String[] args) { SpringApplication.run(DemoServiceApplication.class, args); } }
而後XxxRibbonConfig以及DemoRibbonConfig類上沒有任何註解,好比server
public class XxxRibbonConfig { String listOfServers = "http://192.168.99.100:8080,http://192.168.99.101:8080"; @Bean public ServerList<Server> ribbonServerList() { List<Server> list = Lists.newArrayList(); if (!Strings.isNullOrEmpty(listOfServers)) { for (String s: listOfServers.split(",")) { list.add(new Server(s.trim())); } } return new StaticServerList<Server>(list); } }
因爲類上沒有註解,於是這個時候就跟他們類路徑是否在@ComponentScan掃描的包下面沒有關係了。
把標註@RibbonClient的XxxRibbonConfig以及DemoRibbonConfig放到@ComponentScan掃描的包外面便可。