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

RetryableFeignLoadBalancer

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

public class RetryableFeignLoadBalancer extends FeignLoadBalancer        implements ServiceInstanceChooser {    private final LoadBalancedRetryFactory loadBalancedRetryFactory;    public RetryableFeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig,            ServerIntrospector serverIntrospector,            LoadBalancedRetryFactory loadBalancedRetryFactory) {        super(lb, clientConfig, serverIntrospector);        this.loadBalancedRetryFactory = loadBalancedRetryFactory;        this.setRetryHandler(new DefaultLoadBalancerRetryHandler(clientConfig));    }    @Override    public RibbonResponse execute(final RibbonRequest request,            IClientConfig configOverride) throws IOException {        final Request.Options options;        if (configOverride != null) {            RibbonProperties ribbon = RibbonProperties.from(configOverride);            options = new Request.Options(ribbon.connectTimeout(this.connectTimeout),                    ribbon.readTimeout(this.readTimeout));        }        else {            options = new Request.Options(this.connectTimeout, this.readTimeout);        }        final LoadBalancedRetryPolicy retryPolicy = this.loadBalancedRetryFactory                .createRetryPolicy(this.getClientName(), this);        RetryTemplate retryTemplate = new RetryTemplate();        BackOffPolicy backOffPolicy = this.loadBalancedRetryFactory                .createBackOffPolicy(this.getClientName());        retryTemplate.setBackOffPolicy(                backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);        RetryListener[] retryListeners = this.loadBalancedRetryFactory                .createRetryListeners(this.getClientName());        if (retryListeners != null && retryListeners.length != 0) {            retryTemplate.setListeners(retryListeners);        }        retryTemplate.setRetryPolicy(retryPolicy == null ? new NeverRetryPolicy()                : new FeignRetryPolicy(request.toHttpRequest(), retryPolicy, this,                        this.getClientName()));        return retryTemplate.execute(new RetryCallback<RibbonResponse, IOException>() {            @Override            public RibbonResponse doWithRetry(RetryContext retryContext)                    throws IOException {                Request feignRequest = null;                // on retries the policy will choose the server and set it in the context                // extract the server and update the request being made                if (retryContext instanceof LoadBalancedRetryContext) {                    ServiceInstance service = ((LoadBalancedRetryContext) retryContext)                            .getServiceInstance();                    if (service != null) {                        feignRequest = ((RibbonRequest) request                                .replaceUri(reconstructURIWithServer(                                        new Server(service.getHost(), service.getPort()),                                        request.getUri()))).toRequest();                    }                }                if (feignRequest == null) {                    feignRequest = request.toRequest();                }                Response response = request.client().execute(feignRequest, options);                if (retryPolicy != null                        && retryPolicy.retryableStatusCode(response.status())) {                    byte[] byteArray = response.body() == null ? new byte[] {}                            : StreamUtils                                    .copyToByteArray(response.body().asInputStream());                    response.close();                    throw new RibbonResponseStatusCodeException(                            RetryableFeignLoadBalancer.this.clientName, response,                            byteArray, request.getUri());                }                return new RibbonResponse(request.getUri(), response);            }        }, new LoadBalancedRecoveryCallback<RibbonResponse, Response>() {            @Override            protected RibbonResponse createResponse(Response response, URI uri) {                return new RibbonResponse(uri, response);            }        });    }    @Override    public RequestSpecificRetryHandler getRequestSpecificRetryHandler(            FeignLoadBalancer.RibbonRequest request, IClientConfig requestConfig) {        return new RequestSpecificRetryHandler(false, false, this.getRetryHandler(),                requestConfig);    }    @Override    public ServiceInstance choose(String serviceId) {        return new RibbonLoadBalancerClient.RibbonServer(serviceId,                this.getLoadBalancer().chooseServer(serviceId));    }}
  • RetryableFeignLoadBalancer继承了FeignLoadBalancer,实现了ServiceInstanceChooser接口
  • 其构造器根据clientConfig创建了DefaultLoadBalancerRetryHandler;其choose方法使用的是getLoadBalancer().chooseServer,最后通过RibbonLoadBalancerClient.RibbonServer包装返回
  • 其execute方法首先创建了LoadBalancedRetryPolicy,进而创建retryTemplate,最后通过retryTemplate.execute来实现重试功能;其RetryCallback的doWithRetry方法在retryContext是LoadBalancedRetryContext的条件下会切换下一个service实例来进行重试

小结

RetryableFeignLoadBalancer继承了FeignLoadBalancer,对execute方法使用retryTemplate来实现重试,其中在retryContext是LoadBalancedRetryContext的条件下会切换下一个service实例来进行重试

doc

  • RetryableFeignLoadBalancer