Ribbon-自定义Rule时遇到的问题

一. 现象

单独配置Ribbon配置, 如自定义Rule, 在配置类上@Configuration, 以及@Bean注解下, 必然会出现No qualifying bean of type ‘com.netflix.client.config.IClientConfig’ available 对多provider服务调用时出现服务调用错误的提示: feign.FeignException$NotFound: status 404

二. 原因

Ribbon 配置类不能包含在主程序的@ComponentScan范围内
每一个ServiceId都有她专属的SpringContext
错误使用@Bean使得Rule被lb共享, 实际存在的配置对象只有一个

三. 修改方式

增加对服务provider的rule配置, 形如:

1
2
3
base-service:
ribbon:
NFLoadBalancerRuleClassName: com.xxxx.common.Rule

或者以System.setProperty()方式在启动时设置

1
System.setProperty("base-service" + ".ribbo.NFLoadBalancerRuleClassName",Rule.class.name());

四. 参考资料

https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html

https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers

补充

官网描述

在[Ribbon]官网中对于自定义指定Rule有如下描述:

这个自定义配置类不能放在@ComponentScan扫描的当前包以及子包中,
否则这个自定义的IRule会被所有的Ribbon客户端共享, 会导致一系列的问题.

常规处理方式

根据官网的描述, 不能放在当前包与子包中被扫到, 那么就可以新建一个独立的package, 在其中添加自定义的Rule规则类, 并在主启动类中, 添加@RibbonClient, 在其中指定configuration=自定义的规则类.class

PS:说实话这种方式很繁琐

推荐的方式

复习一下spring里面bean的注入方式, 一般默认使用都是singeton单例形式的, 也就是说正因为这个类是单例的, 才会导致各个Ribbon客户端在初始化时候获取到了同一个对象, 实际上还有prototype这一scope可以选择配置, 伪代码如下:

1
2
3
4
5
@Bean
@Scope(value="prototype")
public IRule myRule(){
return new MyRule();
}

结论
至此, 这一问题顺利解决, 继续撸代码去.