springcloud ribbon retryTemplate操作流程分析
一、在配置中加入
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId> </dependency>二、初始化流程分析
1.構建LoadBalancedRetryFactory,在RibbonAutoConfiguration配置類中。
2.在LoadBalancerAutoConfiguration中構建LoadBalancerRequestFactory負載均衡請求工廠, 以及RetryLoadBalancerInterceptor,并設置在RestTemplate中。
。
?
?三、調用流程分析
1.還是進入RestTemplate.execute方法,
這里的request還是?InterceptingClientHttpRequest
2.進入攔截器調用,這里的攔截器為?RetryLoadBalancerInterceptor
3.RetryTemplate的interrupt方法, 這里先創建一個重試策略,就是判斷當前是否可重試。
package org.springframework.cloud.client.loadbalancer;/*** @author Ryan Baxter* @author Will Tran* @author Gang Li*/ public class RetryLoadBalancerInterceptor implements ClientHttpRequestInterceptor {@Overridepublic ClientHttpResponse intercept(final HttpRequest request, final byte[] body,final ClientHttpRequestExecution execution) throws IOException {final URI originalUri = request.getURI();final String serviceName = originalUri.getHost();Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);final LoadBalancedRetryPolicy retryPolicy = lbRetryFactory.createRetryPolicy(serviceName,loadBalancer);RetryTemplate template = createRetryTemplate(serviceName, request, retryPolicy);return template.execute(context -> {ServiceInstance serviceInstance = null;if (context instanceof LoadBalancedRetryContext) {LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;serviceInstance = lbContext.getServiceInstance();}if (serviceInstance == null) {serviceInstance = loadBalancer.choose(serviceName);}ClientHttpResponse response = RetryLoadBalancerInterceptor.this.loadBalancer.execute(serviceName, serviceInstance,requestFactory.createRequest(request, body, execution));int statusCode = response.getRawStatusCode();if (retryPolicy != null && retryPolicy.retryableStatusCode(statusCode)) {byte[] bodyCopy = StreamUtils.copyToByteArray(response.getBody());response.close();throw new ClientHttpResponseStatusCodeException(serviceName, response, bodyCopy);}return response;}, new LoadBalancedRecoveryCallback<ClientHttpResponse, ClientHttpResponse>() {//This is a special case, where both parameters to LoadBalancedRecoveryCallback are//the same. In most cases they would be different.@Overrideprotected ClientHttpResponse createResponse(ClientHttpResponse response, URI uri) {return response;}});}4.首先創建RetryTemplate,這里面主要綁定InterceptorRetryPolicy攔截器重試策略。
?
5.攔截器重試策略包含了RibbonLoadBalacedRetryPolicy和一個服務實例選擇器。RibbonLoadBalancerClient.
?6.接著真正執行RetryTemplate.execute方法。一個重試回調,一個恢復回調。
@Override public final <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback,RecoveryCallback<T> recoveryCallback) throws E {return doExecute(retryCallback, recoveryCallback, null); }?7.RetryTemplate的doExecute方法,首先判斷是否可重試,可以就調用retryCallback.doWithRetry(context),
org.springframework.retry.support.RetryTemplateprotected <T, E extends Throwable> T doExecute(RetryCallback<T, E> retryCallback,RecoveryCallback<T> recoveryCallback, RetryState state)throws E, ExhaustedRetryException {RetryPolicy retryPolicy = this.retryPolicy;BackOffPolicy backOffPolicy = this.backOffPolicy;// Allow the retry policy to initialise itself...RetryContext context = open(retryPolicy, state);RetrySynchronizationManager.register(context);Throwable lastException = null;boolean exhausted = false;try {// Give clients a chance to enhance the context...boolean running = doOpenInterceptors(retryCallback, context);while (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {try {lastException = null;return retryCallback.doWithRetry(context);}catch (Throwable e) {lastException = e;try {registerThrowable(retryPolicy, state, context, e);}catch (Exception ex) {throw new TerminatedRetryException("Could not register throwable",ex);}finally {doOnErrorInterceptors(retryCallback, context, e);}if (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) {try {backOffPolicy.backOff(backOffContext);}catch (BackOffInterruptedException ex) {throw ex;}}if (this.logger.isDebugEnabled()) {this.logger.debug("Checking for rethrow: count=" + context.getRetryCount());}if (shouldRethrow(retryPolicy, context, state)) {if (this.logger.isDebugEnabled()) {this.logger.debug("Rethrow in retry for policy: count="+ context.getRetryCount());}throw RetryTemplate.<E>wrapIfNecessary(e);}}}exhausted = true;return handleRetryExhausted(recoveryCallback, context, state);}catch (Throwable e) {throw RetryTemplate.<E>wrapIfNecessary(e);}finally {close(retryPolicy, context, state, lastException == null || exhausted);doCloseInterceptors(retryCallback, context, lastException);RetrySynchronizationManager.clear();}}8.這里首先為當前請求創建RetryContext,實現類為LoadBalancedRetryContext
9.判斷是否可以重試接口,判斷重試次數是否為0。
?
?10.接著調用重試函數,又回到RetryLoadBalancerInterceptor。
11.這里的LoadBalancer為RibbonLoadBalanceClient,并且requestFactory.createRequest為之前未重試時普通的HTTP請求類。
ClientHttpResponse response = RetryLoadBalancerInterceptor.this.loadBalancer.execute(serviceName, serviceInstance,requestFactory.createRequest(request, body, execution));?12.LoadBalancerRequestFactory.createRequest又跳到InterceptingRequestExecution這個責任鏈執行器中。
?13.由于這種普通的REQUEST,沒有攔截器,直接調用HTTP請求對象替換實例URL中為真實服務實例域名,然后執行HTTP請求。
?14.請求接口超時,被RetryTemplate.doExecute方法捕獲異常,然后繼續獲取下一個實例重試。?
?
?
這里對retryCnt加1.?
下面重新選擇一個實例,進行設置到context
接著又判斷是否可重試。
?
然后嘗試下一個節點,重新調用retryCallback函數。
?
重新請求成功。
?
攔截器執行完畢,返回成功。注意這個重試攔截器沒有調用execution.interrupt,所以不會再執行責任鏈的下一個HANDLER.
?
?最后處理結果,進行數據轉換,返回數據。
?返回結果完畢。
?
總結
以上是生活随笔為你收集整理的springcloud ribbon retryTemplate操作流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springcloud ribbon 配
- 下一篇: spring cloud feign 加