通過【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]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM