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天,點選檢視活動詳情