閱讀Spring Cloud微服務實戰中的Ribbon源碼分析章節,debug跟蹤源碼後,做此記錄。
從@LoadBalanced註解源碼的註釋中可以知道, 該註解用來給RestTemplate做標記, 以使用負載均衡的客戶端(LoadBalancerClient)來配置它。
在讀完這個章節後,還是沒能理解Ribbon是怎樣爲RestTemplate提供負載均衡。於是debug進行源碼跟蹤,纔算瞭解了大致流程。
從下面這段代碼開始,發起一個GET請求,目標服務爲product,product服務實例有倆個。
@GetMapping("hello")
public String hello(String name){
String result = restTemplate.getForObject("http://product/hello?name={1}", String.class, name);
return result;
}
進入getForObject方法,不斷深入,忽略掉不重要的參數封裝、處理,到下面這段源碼:
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
else {
return null;
}
}
catch (IOException ex) {
...
}
finally {
...
}
}
可以很明顯的看到 request.execute() ,猜一下也能知道這裏要開始真正發起請求了。進入execute方法,執行對象爲AbstractClientHttpRequest類型,繼續進入executeInternal方法,執行對象爲AbstractBufferingClientHttpRequest類型,繼續進入executeInternal方法,執行對象爲AbstractBufferingClientHttpRequest的子類型InterceptingClientHttpRequest,敲黑板,劃重點。十分驚奇的發現該類型中封裝了一個ClientHttpRequestInterceptor的集合,在書中的介紹有說明Ribbon爲RestTemplate的負載均衡提供了一個LoadBalancerInterceptor,並且LoadBalancerInterceptor是直接實現自ClientHttpRequestInterceptor,選中這個Interceptor
沒錯,是他就是他,集合中神奇的被注入了一個LoadBalancerInterceptor實例,那接下來的關注點就是LoadBalancerInterceptor是如何實現負載均衡的。
回到之前追蹤到的位置:
public ClientHttpResponse execute(HttpRequest request, final byte[] body) throws IOException {
if (this.iterator.hasNext()) {
ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
return nextInterceptor.intercept(request, body, this);
}
else {
...
}
}
很明顯,此處開始調用Interceptor進行攔截邏輯處理了。進入intercept方法:
可以看到此處通過request對象獲取到了請求的服務名稱serviceName,此處獲取到的是product。(發現貼入的源碼沒有debug時的變量信息,不太直觀,後面還是貼圖好了。)
此處有一個loadBalancer對象,查看到類型爲:
前面有提到過,LoadBalancerClient是爲RestTemplate提供負載均衡的接口,此處使用的是Ribbon方式的實現類。繼續進入execute方法:
此處有一個getLoadBalancer方法,該方法返回值爲ILoadBalancer接口類型,其實這個類型纔是Ribbon真正的負載均衡器。
getLoadBalancer方法最後是通過spring上下文獲取ILoadBalancer類型實例,默認爲ZoneAwareLoadBalancer,書中有介紹,ILoadBalancer是在RibbonClientConfiguration中配置的。具體配置的代碼片段: 我們繼續執行getServer方法,不斷深入,來到ZoneAvoidanceRule.choose方法,該方法在ZoneAvoidanceRule並未重寫,所以執行的是父類型PredicateBasedRule的choose方法,方法具體如下:
getAllServers方法獲取到所有的服務列表,chooseRoundRobinAfterFiltering方法大致爲篩選出可用的服務列表,以輪詢的方式選擇具體的server並封裝到Optional中,最終返回server,至此我終於拿到了要訪問server對象:
product啓動了倆個實例,mac:8888、mac:9999,此次獲取獲取到的是mac:9999,再講server封裝成RibbonServer,最終執行execute方法向獲取到的server對象發起具體請求。
至此我發現Ribbon爲RestTemplate提供負載均衡的切入點就在InterceptingClientHttpRequest類型,但是爲什麼RestTemplate的Interceptor集合中會有該類型的實例呢?答案在書中也有說明,都是在LoadBalancerAutoConfiguration配置類型中生成的。具體可以查看源碼。