spring-cloud-netflix-ribbon学习笔记(二)LoadBalancerInterceptor的处理逻辑

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

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » spring-cloud-netflix-ribbon学习笔记(二)LoadBalancerInterceptor的处理逻辑