Spring Cloud Alibaba-Ribbon的源碼分析

語言: CN / TW / HK

一、源碼分析

1、猜測源碼的實現

我們在看源碼的時候我們可以根據功能先想一下,他是怎樣實現的,如果讓我們來實現我們會怎麼做,我們想ribbon不過就是替換nx-stock,為ip+端口我們會怎樣做,大家想一下 ? 是不是我們可以增加加一個攔截器, 如下,你這樣有這樣一個思維再去看源碼就應該容易一點:我們RestTemplate有一個擴展點是

ClientHttpRequestInterceptor 我們Ribbon通過LoadBalancerInterceptor實現了這個擴展早點,將nx-stock替換為 192.168.0.3:8003

image.png

image.png

2、初始化的過程

我們首先進入我們的註解@LoadBalanced,我們學spring源碼的時候一般是註解中增加一個@Import,引入一個對象此時他沒有,所以我們想它是和springboot整合的,所以我們可以找到同包下的spring.factories中,看一下,自動裝配類。

我們先進入spring-cloud-starter-netflix-ribbon.2.2.6

.Release 裏面乜有對應spring.factories,他是空的,這和我們講springboot時候説mybatis一樣,starter是空的但是他能引用一些自動配置的jar,我們進去看

image.png

image.png

導入了RibbonAutoConfiguration

image.png

image.png

我們可以全文搜索一下哪裏加載了LoadBalancerAutoConfiguration,

image.png

這樣應該和我們的LoadBalanced註解有關

image.png

AsyncLoadBalancerAutoConfiguration和LoadBalancerAutoConfiguration應該和我們對應的註解有關係,那麼我們想Async是應該和異步有關係應該是更高級的作用,所以我們進入LoadBalancerAutoConfiguration這個類。 我們進入配置類中發現

好這裏面就應該是我們找的類,這裏應該是獲取容器中所有標註@LoadBalanced註解的所有類。

image.png

我們進入LoadBalancerAutoConfiguration 裏面初始化一些對象,

我們這裏初始化一個對象是LoadBalanceInterceptor,這就是一個攔截器,然後後面是一個RestTemplateCustomizer,我們從名字可以看出他就是一個自定義的RestTemplate,我們可以看一下里面內容就有一個customize方法,我們這裏用哪個lambda表達式來處理,就是穿進去一個restTemplate然後給裏面增加一個攔截器。這個攔截器裏面就是上面弄的LoadBalancerInterceptor。

image.png

image.png

接着還有一個對象就是:SmartInitializingSingleton

image.png

這一部分就是給我們的restTemplate增加了攔截器。

image.png

接下來我們就可以進入攔截器查看一下,進入攔截器是不是就查看intercept,寫過攔截器一個知道他最重要的方法就是intercept

3、負載均衡的過程

request.getURI(), 這個不用我多解釋了吧,restTemplate就是發送http請求,這裏獲取他的請求鏈接,然後獲取他的host,他的host是什麼就是nx-stock,就是serviceName,然後將這serviceName傳遞到我們的execute裏面,我們推想這裏很可能對我們serviceName進行解析,從我們的nacos註冊中心獲取註冊列表,然後通過負均衡選擇一個合適的地址,進行調用。

image.png

這裏我麼可以一個看到第一個應該是獲取負載均衡器,第一個是根據負載均衡器來獲取對應的一個服務

image.png

那我們簡單看一下怎樣獲取負載均衡器:

image.png

image.png

image.png

AnnotationConfigApplicationContext 就是我們註解配置的上下文,我們則是從容器中獲取對應的對象,ILoadBalancer對應的負載均衡器。

image.png

我們可以看出是從一個Map裏獲得,如果沒有我們需要創建他createContext

image.png

image.png

獲取配置然後註冊刷新容器,這裏和我們的spring容器一樣。

image.png

所以我們一定有一個地方是創建這個對象,然後注入容器的,那一定是一個配置類,其實他是在RibbonClientConfiguration這個類中。在這裏其實就是我們對應ribbon可配置類的默認配置是在這裏配置,看這裏每個注入類對應的註解@ConditionalOnMissingBean,從這裏我們能知道我們配置了我們自己的類就用我們自己的類,如果沒有配置我們自己的類,就會用到默認的配置類。

從這裏我們能驗證一個事情,@ConditionOnMissingBean中是查看容器中是否有對應的ILoadBalancer如果有則使用,如果沒有則調用這個方法,然後我們看一下這個方法propertiesFactory是查看property中是否設置了我們的配置,如果有則獲取到,沒有則是獲取默認的,

所以這裏證明一個前面的結論: java配置高於屬性配置

image.png

好,看到這裏就可以,當然我們也可以查看一下這個負載均衡器,但裏面對應的內容很複雜,我們知道我們獲取一個負載均衡器就可以了,後面可以不看。等我們後面用的時候再看。

好我們回到剛才的位置:

通過這個名稱getServer我們就應該知道,這個應該是通過負載均衡器中的算法獲取對應一個服務

image.png

這裏是調用這個負載均衡器的chooseServer,通過名稱我們就知道這裏是選擇一個服務,這裏肯定是從nacos中獲取對應的服務列表,然後選擇一個進行調用。

image.png

在這裏我們可以看到我們應該調用ZoneAvoidanceRule

image.png

image.png

進入後我們看到一個關鍵方法就是role.choose,這裏面我們發現他有很多實現,剛才我們説過RibbonClientConfiguration初始化了我們一些默認的對應的類,

image.png

我們可以發現這裏創建了一個默認的規則ZoneAvoidanceRule,所以就會調用他方法,同時我們也要看一下他的集成關係,因為我們調用的方法可能是他的父類中的方法,

image.png

image.png

這裏沒有對應的ZoneAvoidanceRule 但是有PredicateBasedRule,所以會調用這個方法。

image.png

首先獲取一個負載均衡器,然後這裏chooseRoundRobinAfterFiltering 從這個方法我們就知道,這裏使用輪訓方法,ZoneAvoidanceRule如果沒有設置時鐘就會才用輪訓算法,接着這裏通過負載均衡器獲取對應所有的server,我們可以推算這裏是應該是從nacos中獲取對應的服務列表,當然我們先不考慮他是怎樣獲取的,我們先知道他這裏獲取對應的服務列表就可以。

image.png

image.png

下面就輪訓機制獲取對應有效的服務,首先看一下 nextIndex他是AtomicInteger類型,我們首先獲取對應的值,然後加一求餘,得到next值,然後

nextIndex.compareAndSet方法,判斷是否是current這個值,如果是則返回,並且將next值設置進去,方便下一次的獲取,這就是輪訓機制,大家能不能明白,

好,那我們看這裏用掉了cas方式,這樣大大提高了他的性能,如果不用cas的話就需要用到lock,這樣性能就會降低,當然如果設置返回false,他還會進入下一次循環處理是吧, 這就是併發編程中的應用,我們可能在工作中做業務用不到,但是你寫一些中間件或者上大廠這些就用到的很多了,所以併發編程的基本功一定要搞好。

image.png

好,負載均衡我們説完了,我們看一下我們的server是怎麼樣獲取的。

4、獲取服務列表

我們要從我們的負載均衡器中看起,因為我們前面就是從負載均衡器中獲取對應的server列表

image.png

image.png

我們可以進入我們的配置類中RibbonClientConfiguration中查看對應的創建。從這裏構造方法我們可以看到對應的serverList,所以説他是在創建構造方法的時候就已經獲取到對應的服務列表,好我們看他的服務列表是怎麼獲取的。

image.png

好,我們來全文搜索一下 , 這裏是從配置文件中獲取對應的配置server,因為我們的ribbon可以獨立使用的,所以我們這裏獲取的serverlist應該是空的。

image.png

好,這裏我們進入負載均衡器的構造方法裏面。

這裏面有個restofInit方法,好這裏的init方法我們可以進去看看,看到這個init或者start方式都是重要方法,我們可以進去看一下

image.png

看這個方法,我們可以翻譯一下 這裏 了開啟並初始化學習新服務的特點, 這是什麼意思我們可以看一下

image.png

image.png

他們最後會調用這個updateListOfServers方法,這個是重點後面我們會看到。

=image.png

image.png

image.png

image.png

獲取實例

image.png

這裏就和nacos中獲取數據

image.png

image.png

5、更新服務列表

image.png

image.png

image.png

進行服務賦值,後面就可以使用了

image.png

6、重構請求的URL

image.png

此時我們需要debug進入這個容器中:

image.png

image.png

路跟下來發現在⼀個匿名內部類中,發現了很可疑的地點:ServiceRequestWrapper,服務請求的⼀個

包裝類,難不成在這⾥重構請求,有點接近了,進去看下:

image.png

image.png

debug進入就會發現裏面對host的替換

image.png

image.png

持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第10天,點擊查看活動詳情