Feign调用可重试的最佳方案分享
作者:JAVA旭阳 发布时间:2021-06-09 12:19:23
标签:Feign,调用,可重试
前言
在我们公司里,不同的服务之间通过Feign
进行远程调用,但是,我们在尝试使调用可重试时遇到了一个小问题,Feign
框架本身可以配置的自己的重试机制,但是它是一刀切的方式,所有的调用都是同样的机制,没有办法像我们希望的那样在每个方法的基础上配置。不过我在项目中探索除了一种新的写法,通过spring-retry
框架集合Feign
去实现重试机制,可以为每个调用实现不同的重试机制,那究竟是如何做到的呢,继续往下看呀。
自定义注解@FeignRetry
为了解决上面提到的问题,让Feign调用的每个接口单独配置不同的重试机制。我们使用了面向切面编程并编写了一个自定义注解:@FeignRetry
。此注释的工作方式类似于@Retryable
的包装器,并与其共享相同的规范以避免混淆。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FeignRetry {
Backoff backoff() default @Backoff();
int maxAttempt() default 3;
Class<? extends Throwable>[] include() default {};
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Backoff {
long delay() default 1000L;;
long maxDelay() default 0L;
double multiplier() default 0.0D;;
}
FeignRetryAspect
切面处理@FeignRetry
注解。
Slf4j
@Aspect
@Component
public class FeignRetryAspect {
@Around("@annotation(FeignRetry)")
public Object retry(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = getCurrentMethod(joinPoint);
FeignRetry feignRetry = method.getAnnotation(FeignRetry.class);
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setBackOffPolicy(prepareBackOffPolicy(feignRetry));
retryTemplate.setRetryPolicy(prepareSimpleRetryPolicy(feignRetry));
// 重试
return retryTemplate.execute(arg0 -> {
int retryCount = arg0.getRetryCount();
log.info("Sending request method: {}, max attempt: {}, delay: {}, retryCount: {}",
method.getName(),
feignRetry.maxAttempt(),
feignRetry.backoff().delay(),
retryCount
);
return joinPoint.proceed(joinPoint.getArgs());
});
}
private BackOffPolicy prepareBackOffPolicy(FeignRetry feignRetry) {
if (feignRetry.backoff().multiplier() != 0) {
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(feignRetry.backoff().delay());
backOffPolicy.setMaxInterval(feignRetry.backoff().maxDelay());
backOffPolicy.setMultiplier(feignRetry.backoff().multiplier());
return backOffPolicy;
} else {
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(feignRetry.backoff().delay());
return fixedBackOffPolicy;
}
}
private SimpleRetryPolicy prepareSimpleRetryPolicy(FeignRetry feignRetry) {
Map<Class<? extends Throwable>, Boolean> policyMap = new HashMap<>();
policyMap.put(RetryableException.class, true); // Connection refused or time out
policyMap.put(ClientException.class, true); // Load balance does not available (cause of RunTimeException)
if (feignRetry.include().length != 0) {
for (Class<? extends Throwable> t : feignRetry.include()) {
policyMap.put(t, true);
}
}
return new SimpleRetryPolicy(feignRetry.maxAttempt(), policyMap, true);
}
private Method getCurrentMethod(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
return signature.getMethod();
}
}
捕获FeignRetry
注解的方法,将配置传递给Spring RetryTemplate
,根据配置调用服务。
@FeignRetry 的使用
用法很简单,只需将注释放在我们希望重试机制处于活动状态的 Feign Client
方法上即可。自定义切面的用法类似于Spring自带的@Retryable
注解。
@GetMapping
@FeignRetry(maxAttempt = 3, backoff = @Backoff(delay = 500L))
ResponseEntity<String> retrieve1();
@GetMapping
@FeignRetry(maxAttempt = 6, backoff = @Backoff(delay = 500L, maxDelay = 20000L, multiplier = 4))
ResponseEntity<String> retrieve2();
另外还需要在应用程序类中使用 @EnableRetry
注释来启动重试,比如可以加载SpringBoot的启动类中。
来源:https://juejin.cn/post/7187252990821007397
0
投稿
猜你喜欢
- 一、demo简介1.效果展示如下图,我截了三个瞬间,但其实这是一个连续的动画,就是这个大圆不停地吞下小圆。2.这个动画可以拆分为两部分,首先
- Feign调用服务Headers传参在使用springcloud中经常会出现个服务调用,一般情况下会在Headers加上token的验证,那
- ThreadLocal简介变量值的共享可以使用public static的形式,所有线程都使用同一个变量,如果想实现每一个线程都有自己的共享
- @SuppressWarnings 注解@SuppressWarnings: 抑制编译器警告如下,可以看到idea中有警告的颜色标注当我们不
- 一、连接数据库的配置单独放在一个properties文件中之前,我们是直接将数据库的连接配置信息写在了MyBatis的conf.xml文件中
- 由于公司的开发团队偏向于使用Java技术,而且公司倡导学习开源技术,所以我选择用Java语言来进行Selenium WebDriver的自动
- 一、前言今天实现一个时钟工具,其实在之前已经完成了一个简单的时钟工具:【Unity3D应用案例系列】时钟、钟表小组件开发。那么,今天的这个小
- Spring Security登录表单配置1.引入pom依赖创建一个Spring Boot工程,引入Web和Spring Security依
- Apache 和 Tomcat 都是web网络服务器,两者既有联系又有区别,在进行HTML、PHP、JSP、P
- Java 1.0 IO系统介绍1 Java IO版本Java库的IO分为输入/输出两部分。早期的Java 1.0版本的输入系统是InputS
- Java线程池并发执行多个任务Java在语言层面提供了多线程的支持,线程池能够避免频繁的线程创建和销毁的开销,因此很多时候在项目当中我们是使
- Lambda表达式的进化之路为什么要使用Lambda表达式可以简洁代码,提高代码的可读性可以避免匿名内部类定义过多导致逻辑紊乱在原先实现接口
- java 中模式匹配算法-KMP算法实例详解朴素模式匹配算法的最大问题就是太低效了。于是三位前辈发表了一种KMP算法,其中三个字母分别是这三
- SessionSession对象用于获取与数据库的物理连接。 Session对象是重量轻,设计了一个互动是需要与数据库每次被实例化。持久化对
- 持久层的那些事什么是 JDBCJDBC(JavaDataBase Connectivity)就是 Java 数据库连接, 说的直白点就是 使
- 迭代器模式,一直没用过,也不会用。恰巧MyBatis框架中也使用到了迭代器模式,而且看起来还比较简单,在以后的工作中,若有需要咱们可模仿它的
- 快速排序算法概念快速排序一般基于递归实现。其思路是这样的:1.选定一个合适的值(理想情况中值最好,但实现中一般使用数组第一个值),称为“枢轴
- 前言痛点:在java开发的过程中,我们经常要面对各种各样的环境,比如开发环境,测试环境,正式环境,而这些环境对项目的需求也不相同。在此之前,
- 1.打开官网稍微学习一下,了解一下spring cloud是个什么东西,大概有哪些组件等https://spring.io/projects
- kotlin是一门基于jvm的编程语言,最近进行了关于kotlin和 anko的研究。并且结合现在的APP设计模式,设想了初步的开发方式。并