通过【application.yml】配置自定义Ribbon客户端时参数【listOfServers】不起作用

1、今天按照SpringCloud系列九:脱离Eureka使用Ribbon - 禁忌夜色153 - 博客园的介绍,通过【application.yml】自定义配置Ribbon客户端时,发现配置的【listOfServers】不起作用。

2、追查了半天原来是因为没有严格按照文章的步骤去做导致的,最主要的原因是因为没有将依赖【spring-cloud-starter-netflix-eureka-client】去掉。

3、为什么没有这个依赖会导致配置失效呢?因为Ribbon对每个客户端,会依据Spring上下文的方式也为其生成一个Spring上下文的执行环境。在这个过程中,会先通过Spring环境参数中由【客户端名称和Ribbon命名空间【ribbon】】组成前缀的特定参数生成【IClientConfig】类型的配置Bean,然后再由配置类后置处理器扫描到Bean定义并生成Bean。其中就包括通过配置类【RibbonClientConfiguration】中@Bean方法【ribbonLoadBalancer】获取负载均衡器。

clip_image001[6]

4、在执行该方法生成负载均衡器时,需要由客户端专用的Spring【BeanFactory】根据Bean定义提供所需的各个参数,其中就包括【ServerList<Server>】类型的参数【serverList】。

clip_image002[6]

5、问题就出现在这个参数的获取上,在配置类【RibbonClientConfiguration】和【EurekaRibbonClientConfiguration】中均定义了获取该参数实例的@Bean方法【ribbonServerList】,并且都被【@ConditionalOnMissingBean】注解。这两者在上下文环境即配置文件中未指定参数【NIWSServerListClassName】的值时将会返回不同的默认类型。【RibbonClientConfiguration】返回的是从参数【listOfServers】中获取服务器列表的【ConfigurationBasedServerList】,而【EurekaRibbonClientConfiguration】返回的是从Eureka服务端获取服务器列表的【DomainExtractingServerList】。

clip_image003[6]

clip_image004[6]

clip_image005[6]

clip_image006[6]

6、那为什么配置类【EurekaRibbonClientConfiguration】会优先于【RibbonClientConfiguration】呢?这是由于每个客户端的专用Spring上下文是由【SpringClientFactory】生成的,而它是有由两个配置属性【configurations】和【defaultConfigType】,都是用来指定配置类。其中【configurations】是在应用启动时由配置类【RibbonAutoConfiguration】通过@Bean方法【springClientFactory】从全局Spring上下文中获取的,也就是通过注解【@RibbonClients】和【@RibbonClient】指定的Ribbon配置。

虽然在【SpringClientFactory】初始化时指定了【defaultConfigType】为配置类【RibbonClientConfiguration】,但在应用这两个属性创建客户端专用的Spring上下文时,属性【configurations】是优先于【defaultConfigType】,再加上注解【@ConditionalOnMissingBean】的作用,这也就决定了【RibbonClientConfiguration】里面的@Bean方法【ribbonServerList】无法形成Bean定义,从而也无法加入到【BeanFactory】的Bean定义集合中,也就是无效的。从而导致参与【ribbonLoadBalancer】创建的参数【ribbonServerList】都是由【EurekaRibbonClientConfiguration】生成的类型为【DomainExtractingServerList】的Bean。

clip_image007[6]

clip_image008[6]

clip_image009[6]

7、那如何解决【listOfServers】的问题呢?最简单的就是移除依赖【spring-cloud-starter-netflix-eureka-client】,在不移除该依赖的情况下,可以通过在配置文件中指定参数【NIWSServerListClassName】为【com.netflix.loadbalancer.ConfigurationBasedServerList】。除了这两种方法外还有一种方法可以实现,就是不让配置类【EurekaRibbonClientConfiguration】生效。虽然该配置类本身无法设置,但是通过【@RibbonClients】将其引入的配置类【RibbonEurekaAutoConfiguration】却可以设置启用开关。只需设置属性【ribbon.eureka.enabled】为false,即可阻止其对Spring上下文生效。

clip_image010[6]

clip_image011[6]

8、在追踪这个问题时还发现了另一个情况,就是在自定义的规则中会先定义一个【ILoadBalancer】类型的属性。其实这个属性是否进行初始化是无所谓的,因为在以其实例作为构建参数来初始化真正的【BaseLoadBalancer】时,该属性会被替换为真正的【BaseLoadBalancer】实例,并且会里外替换两遍。

clip_image012[6]

clip_image013[6]

clip_image014[6]

原文地址:https://www.cnblogs.com/StarkBrothers/p/12173252.html