上一篇講到,Ribbon與Spring-Cloud整合以後,會給RestTemplate
加上一個LoadBalancerInterceptor
的攔截器,那麼現在就來看看LoadBalancerInterceptor
裏面的邏輯吧~話不多說,先上代碼:
package org.springframework.cloud.client.loadbalancer;
import java.io.IOException;
import java.net.URI;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.Assert;
/**
* @author Spencer Gibb
* @author Dave Syer
* @author Ryan Baxter
* @author William Tran
*/
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName,
this.requestFactory.createRequest(request, body, execution));
}
}
第一步:
這裏可以看到LoadBalancerInterceptor
有兩個屬性,一個是LoadBalancerClient
,其實現子類是org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient
;另一個是LoadBalancerRequestFactory
。而intercept
就是實際攔截的方法了。可以看到intercept
方法先是拿到了請求和uri和serviceName,並且在serviceName爲null的情況下報了個錯。接着就是使用LoadBalancerClient
來真正的執行請求方法。不過這裏先不看它是怎麼執行的,先抱着好奇的心態來看一下LoadBalancerRequestFactory
是怎麼創建一個Request的。
public class LoadBalancerRequestFactory {
private LoadBalancerClient loadBalancer;
private List<LoadBalancerRequestTransformer> transformers;
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer,
List<LoadBalancerRequestTransformer> transformers) {
this.loadBalancer = loadBalancer;
this.transformers = transformers;
}
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer) {
this.loadBalancer = loadBalancer;
}
public LoadBalancerRequest<ClientHttpResponse> createRequest(
final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) {
return instance -> {
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
this.loadBalancer);
if (this.transformers != null) {
for (LoadBalancerRequestTransformer transformer : this.transformers) {
serviceRequest = transformer.transformRequest(serviceRequest,
instance);
}
}
return execution.execute(serviceRequest, body);
};
}
}
第二步:
這裏可以看到createRequest
方法使用java8的lambda語法創建了一個匿名的LoadBalancerRequest
類,內部處理邏輯是: 先是把HttpRequest
包裝成了ServiceRequestWrapper
,然後判斷了transformers
爲不爲空,但是筆者發現這個接口好像在當前項目中沒有實現類,而且看接口好像也是給HttpRequest
處理一下,接口方法:HttpRequest transformRequest(HttpRequest request, ServiceInstance instance);
,這裏就先不管他了。最後執行了ClientHttpRequestExecution
的execute
方法。那我們在跟過去看一看。
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
if (this.iterator.hasNext()) {
ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
return nextInterceptor.intercept(request, body, this);
}
else {
HttpMethod method = request.getMethod();
Assert.state(method != null, "No standard HTTP method");
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));
if (body.length > 0) {
if (delegate instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));
}
else {
StreamUtils.copy(body, delegate.getBody());
}
}
return delegate.execute();
}
}
第三步:
這裏就發現了很神奇的事了,一開始就來判斷了是否還有下一個攔截器,如果有,就繼續執行攔截器的邏輯,又回到了最開始的一步(LoadBalancerInterceptor.intercept方法
),否則就執行請求。
總結:
目前就知道了攔截器是怎麼工作的,接下來就要看看看第一步中的(this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
)LoadBalancerClient的excute方法了。