order
This paper mainly studies the RetryableFeignLoadBalancer of spring cloud
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 inherits FeignLoadBalancer and implements ServiceInstanceChooser interface.
- Its constructor creates the DefaultLoadBalancerRetryHandler according to clientConfig; its choose method uses getLoadBalancer().chooseServer, and finally returns it through the RibbonLoadBalancerClient.RibbonServer wrapper.
- Its execute method first creates the LoadBalancedRetryPolicy, then creates the retryTemplate, and finally implements the retry function through retryTemplate.execute; its RetryCallback's doWithRetry method will switch to the next service instance for retry when the retryContext is LoadBalancedRetryContext.
Summary
RetryableFeignLoadBalancer inherits FeignLoadBalancer. retryTemplate is used to retry the execute method. When retryContext is LoadBalancedRetryContext, the next service instance will be switched to retry.