转载

聊聊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<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
原文  https://segmentfault.com/a/1190000019737170
正文到此结束
Loading...