序
本文主要研究一下 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<String, Collection<String>> headers = new LinkedHashMap<>(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<String, List<String>> headers = new HashMap<>();
Map<String, Collection<String>> feignHeaders = RibbonRequest.this
.toRequest().headers();
for (String key : feignHeaders.keySet()) {headers.put(key, new ArrayList<String>(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<String, Collection<String>> getHeaders() {return this.response.headers();
}
Response toResponse() {return this.response;}
@Override
public void close() throws IOException {if (this.response != null && 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
- FeignLoadBalancer