前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于ribbonClient配置的一个坑

关于ribbonClient配置的一个坑

作者头像
code4it
发布2018-09-17 14:43:30
3.2K0
发布2018-09-17 14:43:30
举报
文章被收录于专栏:码匠的流水账码匠的流水账

不知道从哪个版本起,给ribbon配置物理的server list起,单纯配置xxx.ribbon.listOfServers不起效果了,于是就开启了埋坑之旅。

目前使用的是Camden.SR6版本

异常

代码语言:javascript
复制
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>)

复现条件

  • 采用了RibbonClient来指定server list
  • 没有使用@RibbonClients指定,把标注RibbonClient配置类放在了@ComponentScan扫描包下
  • 有多个服务这样指定
  • 而且其中还有一个服务使用load balanced restTemplate的时候,url中的服务名写错了,写成了一个不存在的服务名(当时是把外部的服务名改了导致的)

导致使用到了错误的server list。

问题配置

代码语言:javascript
复制
@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扫描的包下面 查看/beans

代码语言:javascript
复制
{
"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.java

代码语言:javascript
复制
    @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配置,于是就采用了全局的。

解决方案

解决方案很简单,就是修改为正确的服务名就可以了。另外一个方案就是不使用RibbonClient配置,最简单的就是配置文件添加NIWSServerListClassName属性:

代码语言:javascript
复制
xxx:
  ribbon:
    ReadTimeout: 60000
    ConnectTimeout: 60000
      NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
      listOfServers: http://192.168.99.100:8080,http://192.168.99.101:8080

规避全局ribbonServerList的方案

在不使用NIWSServerListClassName属性配置,使用RibbonClient配置的前提下,如何规避全局ribbonServerList呢?

方案1:使用@RibbonClients配置

代码语言:javascript
复制
@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类上没有任何注解,比如

代码语言:javascript
复制
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扫描的包下面没有关系了。

方案2

把标注@RibbonClient的XxxRibbonConfig以及DemoRibbonConfig放到@ComponentScan扫描的包外面即可。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 异常
  • 复现条件
    • 问题配置
    • 解决方案
    • 规避全局ribbonServerList的方案
      • 方案1:使用@RibbonClients配置
        • 方案2
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档