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操作流程分析相关推荐
- 深入分析Ribbon源码分析
本文来分析下Ribbon源码 文章目录 Ribbon源码分析 负载均衡器 AbstractLoadBalancer BaseLoadBalancer DynamicServerListLoadBala ...
- Java微服务组件Spring cloud ribbon源码分析
微服务组件Spring Cloud Ribbon源码分析_哔哩哔哩_bilibili Ribbon源码分析 | ProcessOn免费在线作图,在线流程图,在线思维导图 | 1.什么是ribbon? ...
- SpringCloud详解原理分析
目录 一.微服务优缺点 1.优点 2.缺点 3.微服务技术栈有哪些 二.Spring Cloud 1.核心组件 2.SpringCloud 和 SpringBoot 关系 3.Dubbo 和 Spri ...
- springcloud ribbon @LoadBalance负载均衡源码流程分析
一.编写示例 1.服务端 pom.xml <properties><java.version>1.8</java.version><spring-cloud. ...
- SpringCloud源码:Ribbon负载均衡分析
本文主要分析 SpringCloud 中 Ribbon 负载均衡流程和原理. SpringCloud版本为:Edgware.RELEASE. 一.时序图 和以前一样,先把图贴出来,直观一点: 二.源码 ...
- SpringCloud ribbon源码
1. 基本使用 server.port=8080spring.application.name=ribbon-clientxxx-server.ribbon.listOfServers=localho ...
- Zuul ribbon 重试失效分析
Zuul ribbon 重试机制 问题描述: Zuul转发POST请求接口异常,read timeout,没有进行重试,期望进行重试! 配置参数模拟 spring.cloud.loadbalancer ...
- SpringCloud Ribbon(一)之自定义负载均衡器ILoadBalancer
一.Ribbon负载均衡 一个服务对应一个LoadBalancer,一个LoadBalancer只有一个Rule,LoadBalancer记录服务的注册地址,提供更新服务的注册地址,Rule提供从服务 ...
- SpringCloud Ribbon(二)之自定义负载均衡策略IRule
一.Ribbon负载均衡策略 一个服务对应一个LoadBalancer,一个LoadBalancer只有一个Rule,LoadBalancer记录服务的注册地址,Rule提供从服务的注册地址中找出一个 ...
最新文章
- java redis 主从 哨兵_Redis主从复制与哨兵机制
- python将数字转变为中文读法-Python实现把数字转换成中文
- hdu 1016 Prime Ring Problem(DFS)
- Android高通平台下编译时能生成(拷贝)预编译的so到system的lib目录
- 利用系统提供的崩溃日志解Native层Bug
- 【MFC】MFC开发之前言
- Jdk1.8新特性(二)——lambda表达式(参数列表)-{}和函数式接口@FunctionalInterface
- java输入流的控制_Java-Android-IO流-控制台输入输出
- 【C语言简单说】八:分支结构之if(1)
- oracle display set,Check if the DISPLAY variable is set
- shell脚本之从1加到100之和的思路
- android vrs技术,VRS技术分析研究及应用
- clickhouse创建外部字典表
- libtorrent源码分析(三)BT下载相关知识总结
- 网站域名被墙(被封锁、被屏蔽、被和谐)后最好的解决方法
- Mysql-binlog日志分析
- XMLHttpRequest对象的readyState与status
- 华为云CDN是怎么为你的下载加速保驾护航
- 字符串及有效长度(字节数)计算
- 怎样搜索计算机文档,怎么样快速搜索电脑文件 Windows系统秒搜电脑文件