關(guān)于ribbonClient配置的一個(gè)坑

不知道從哪個(gè)版本起(目測(cè)跟版本無關(guān),應(yīng)該是ribbon.eureka.enabled=true的情況下),給ribbon配置物理的server list起,單純配置xxx.ribbon.listOfServers不起效果了,于是就開啟了埋坑之旅。

目前使用的是Camden.SR6版本

異常

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>)

復(fù)現(xiàn)條件

  • 采用了RibbonClient來指定server list
  • 沒有使用@RibbonClients指定,把標(biāo)注RibbonClient配置類放在了@ComponentScan掃描包下
  • 有多個(gè)服務(wù)這樣指定
  • 而且其中還有一個(gè)服務(wù)使用load balanced restTemplate的時(shí)候,url中的服務(wù)名寫錯(cuò)了,寫成了一個(gè)不存在的服務(wù)名(當(dāng)時(shí)是把外部的服務(wù)名改了導(dǎo)致的)

導(dǎo)致使用到了錯(cuò)誤的server list。

問題配置

@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);
    }
}

這個(gè)的問題是把這個(gè)配置放到了@ComponentScan掃描的包下面
查看/beans

{
"bean": "ribbonServerList",
"aliases": [],
"scope": "singleton",
"type": "org.springframework.cloud.netflix.ribbon.StaticServerList",
"resource": "class path resource [com/xxx/XxxRibbonConfig.class]",
"dependencies": []
}

會(huì)發(fā)現(xiàn)多個(gè)ribbonClient的話,其中一個(gè)的ribbonServerList注冊(cè)為全局的了。(為什么會(huì)注冊(cè)為全局的?)而spring-cloud-netflix-core-1.2.6.RELEASE-sources.jar!/org/springframework/cloud/netflix/ribbon/RibbonClientConfiguration.java

    @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;
    }

這里發(fā)現(xiàn)已經(jīng)有了ribbonServerList,而且沒有找到指定的服務(wù)名的server list配置,于是就采用了全局的。

解決方案

解決方案很簡(jiǎn)單,就是修改為正確的服務(wù)名就可以了。另外一個(gè)方案就是不使用RibbonClient配置,最簡(jiǎn)單的就是配置文件添加NIWSServerListClassName屬性:

xxx:
  ribbon:
    ReadTimeout: 60000
    ConnectTimeout: 60000
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    listOfServers: http://192.168.99.100:8080,http://192.168.99.101:8080

規(guī)避全局ribbonServerList的方案

在不使用NIWSServerListClassName屬性配置,使用RibbonClient配置的前提下,如何規(guī)避全局ribbonServerList呢?

方案1:使用@RibbonClients配置

@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類上沒有任何注解,比如

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);
    }
}

由于類上沒有注解,因而這個(gè)時(shí)候就跟他們類路徑是否在@ComponentScan掃描的包下面沒有關(guān)系了。

方案2

把標(biāo)注@RibbonClient的XxxRibbonConfig以及DemoRibbonConfig放到@ComponentScan掃描的包外面即可。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,635評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,278評(píng)論 6 342
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,168評(píng)論 25 708
  • 舊時(shí),鳳莊有一富賈,名叫唐福,幼年時(shí)家境破落,窮困潦倒,但他志向高遠(yuǎn),又聰慧有機(jī)智,在縣里布莊幫工,學(xué)有所成,之后...
    小黑說閱讀 381評(píng)論 0 0
  • 【2017年01月18星期三——咖啡冥想】 財(cái)富目標(biāo):我近期最想實(shí)現(xiàn)的一個(gè)愿望或目標(biāo)是:保險(xiǎn)每個(gè)月業(yè)績(jī)?cè)鲩L(zhǎng)2倍,收...
    熱瓦昆空閱讀 164評(píng)論 0 0

友情鏈接更多精彩內(nèi)容