22°

聊聊spring cloud的FeignLoadBalancer

本文主要研究一下spring cloud的FeignLoadBalancer

FeignLoadBalancer

spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/ribbon/FeignLoadBalancer.java

public class FeignLoadBalancer extends
		AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> {
private final RibbonProperties ribbon;

protected int connectTimeout;

protected int readTimeout;

protected IClientConfig clientConfig;

protected ServerIntrospector serverIntrospector;

public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig,
		ServerIntrospector serverIntrospector) {
	super(lb, clientConfig);
	this.setRetryHandler(RetryHandler.DEFAULT);
	this.clientConfig = clientConfig;
	this.ribbon = RibbonProperties.from(clientConfig);
	RibbonProperties ribbon = this.ribbon;
	this.connectTimeout = ribbon.getConnectTimeout();
	this.readTimeout = ribbon.getReadTimeout();
	this.serverIntrospector = serverIntrospector;
}

@Override
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
		throws IOException {
	Request.Options options;
	if (configOverride != null) {
		RibbonProperties override = RibbonProperties.from(configOverride);
		options = new Request.Options(override.connectTimeout(this.connectTimeout),
				override.readTimeout(this.readTimeout));
	}
	else {
		options = new Request.Options(this.connectTimeout, this.readTimeout);
	}
	Response response = request.client().execute(request.toRequest(), options);
	return new RibbonResponse(request.getUri(), response);
}

@Override
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
		RibbonRequest request, IClientConfig requestConfig) {
	if (this.ribbon.isOkToRetryOnAllOperations()) {
		return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
				requestConfig);
	}
	if (!request.toRequest().httpMethod().name().equals("GET")) {
		return new RequestSpecificRetryHandler(true, false, this.getRetryHandler(),
				requestConfig);
	}
	else {
		return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
				requestConfig);
	}
}

@Override
public URI reconstructURIWithServer(Server server, URI original) {
	URI uri = updateToSecureConnectionIfNeeded(original, this.clientConfig,
			this.serverIntrospector, server);
	return super.reconstructURIWithServer(server, uri);
}

//......

}

  • FeignLoadBalancer继承了AbstractLoadBalancerAwareClient,它的构造器接收ILoadBalancer、IClientConfig、ServerIntrospector,设置的retryHandler为RetryHandler.DEFAULT
  • 其execute方法首先构造Request.Options,然后通过request.client().execute来获取Response,最后返回RibbonResponse
  • FeignLoadBalancer还覆盖了getRequestSpecificRetryHandler方法,针对ribbon.isOkToRetryOnAllOperations()来构建不同的RequestSpecificRetryHandler;还覆盖了reconstructURIWithServer方法,它使用RibbonUtils的updateToSecureConnectionIfNeeded来构建URI

RibbonRequest

spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/ribbon/FeignLoadBalancer.java

	protected static class RibbonRequest extends ClientRequest implements Cloneable {
	private final Request request;

	private final Client client;

	protected RibbonRequest(Client client, Request request, URI uri) {
		this.client = client;
		setUri(uri);
		this.request = toRequest(request);
	}

	private Request toRequest(Request request) {
		Map&lt;String, Collection&lt;String&gt;&gt; headers = new LinkedHashMap&lt;&gt;(
				request.headers());
		return Request.create(request.httpMethod(), getUri().toASCIIString(), headers,
				request.requestBody());
	}

	Request toRequest() {
		return toRequest(this.request);
	}

	Client client() {
		return this.client;
	}

	HttpRequest toHttpRequest() {
		return new HttpRequest() {
			@Override
			public HttpMethod getMethod() {
				return HttpMethod
						.resolve(RibbonRequest.this.toRequest().httpMethod().name());
			}

			@Override
			public String getMethodValue() {
				return getMethod().name();
			}

			@Override
			public URI getURI() {
				return RibbonRequest.this.getUri();
			}

			@Override
			public HttpHeaders getHeaders() {
				Map&lt;String, List&lt;String&gt;&gt; headers = new HashMap&lt;&gt;();
				Map&lt;String, Collection&lt;String&gt;&gt; feignHeaders = RibbonRequest.this
						.toRequest().headers();
				for (String key : feignHeaders.keySet()) {
					headers.put(key, new ArrayList&lt;String&gt;(feignHeaders.get(key)));
				}
				HttpHeaders httpHeaders = new HttpHeaders();
				httpHeaders.putAll(headers);
				return httpHeaders;

			}
		};
	}

	public Request getRequest() {
		return this.request;
	}

	public Client getClient() {
		return this.client;
	}

	@Override
	public Object clone() {
		return new RibbonRequest(this.client, this.request, getUri());
	}

}

  • RibbonRequest继承了ClientRequest实现了Cloneable接口,它提供了toHttpRequest方法来将feign的Request转换为spring的HttpRequest

RibbonResponse

spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/ribbon/FeignLoadBalancer.java

	protected static class RibbonResponse implements IResponse {
	private final URI uri;

	private final Response response;

	protected RibbonResponse(URI uri, Response response) {
		this.uri = uri;
		this.response = response;
	}

	@Override
	public Object getPayload() throws ClientException {
		return this.response.body();
	}

	@Override
	public boolean hasPayload() {
		return this.response.body() != null;
	}

	@Override
	public boolean isSuccess() {
		return this.response.status() == 200;
	}

	@Override
	public URI getRequestedURI() {
		return this.uri;
	}

	@Override
	public Map&lt;String, Collection&lt;String&gt;&gt; getHeaders() {
		return this.response.headers();
	}

	Response toResponse() {
		return this.response;
	}

	@Override
	public void close() throws IOException {
		if (this.response != null &amp;&amp; this.response.body() != null) {
			this.response.body().close();
		}
	}

}

  • RibbonResponse实现了IResponse接口,将feign的Response适配为netflix的IResponse

小结

  • FeignLoadBalancer继承了AbstractLoadBalancerAwareClient,它的构造器接收ILoadBalancer、IClientConfig、ServerIntrospector,设置的retryHandler为RetryHandler.DEFAULT
  • 其execute方法首先构造Request.Options,然后通过request.client().execute来获取Response,最后返回RibbonResponse
  • FeignLoadBalancer还覆盖了getRequestSpecificRetryHandler方法,针对ribbon.isOkToRetryOnAllOperations()来构建不同的RequestSpecificRetryHandler;还覆盖了reconstructURIWithServer方法,它使用RibbonUtils的updateToSecureConnectionIfNeeded来构建URI

doc

本文由【go4it】发布于开源中国,原文链接:https://my.oschina.net/go4it/blog/3073101

全部评论: 0

    我有话说: