ribbon學習筆記(二)LoadBalancerInterceptor的處理邏輯

    上一篇講到,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);,這裏就先不管他了。最後執行了ClientHttpRequestExecutionexecute方法。那我們在跟過去看一看。

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方法了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章