前言

在我们公司里,不同的服务之间通过Feign进行远程调用,但是,我们在尝试使调用可重试时遇到了一个小问题,Feign框架本身可以配置的自己的重试机制,但是它是一刀切的方式,所有的调用都是同样的机制,没有办法像我们希望的那样在每个方法的基础上配置。不过我在项目中探索除了一种新的写法,通过spring-retry框架集合Feign去实现重试机制,可以为每个调用实现不同的重试机制,那究竟是如何做到的呢,继续往下看呀。

欢迎关注个人公众号『JAVA旭阳』交流沟通

自定义注解@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的启动类中。

总结

Feign重试其实是一个很常见的场景,我们本文通过了自定义了一个@FeignRetry注解来实现可重试的机制,针对不同的Feign接口还可以使用不同的重试策略,是不是很方便,快在你的项目中用起来吧。

欢迎关注个人公众号『JAVA旭阳』交流沟通

这可能是Feign调用可重试的最佳方案了的更多相关文章

  1. SpringCloud Feign 之 超时重试次数探究

    SpringCloud Feign 之 超时重试次数探究 上篇文章,我们对Feign的fallback有一个初步的体验,在这里我们回顾一下,Fallback主要是用来解决依赖的服务不可用或者调用服务失 ...

  2. Spring Cloud Feign 自定义配置(重试、拦截与错误码处理) 实践

    Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 目录 Spring Cloud Feign 自定义配置(重试.拦截与错误码处理) 实践 引子 FeignClient的 ...

  3. SpringCloud:Feign调用接口不稳定问题以及如何设置超时

    1. Feign调用接口不稳定报错 Caused by: java.net.SocketException: Software caused connection abort: recv failed ...

  4. SpringCloud使用Feign调用其他客户端带参数的接口,传入参数为null或报错status 405 reading IndexService#del(Integer);

    SpringCloud使用Feign调用其他客户端带参数的接口,传入参数为null或报错status 405 reading IndexService#del(Integer); 第一种方法: 如果你 ...

  5. spring cloud 微服务调用--ribbon和feign调用

    这里介绍ribbon和feign调用两种通信服务调用方式,同时介绍如何引入第三方服务调用.案例包括了ribbon负载均衡和hystrix熔断--服务降级的处理,以及feign声明式服务调用.例子包括s ...

  6. feign调用超时

    Feign调用超时 feign调用超时 默认feign调用超时是1秒,断点调试是否调用成功肯定超时 feign.hystrix.enabled=true #feign调用默认是1000毫秒=1秒 ad ...

  7. feign调用接口session丢失解决方案

    微服务使用feign相互之间调用时,因为feign默认不传输Header,存在session丢失的问题.例如,使用Feign调用某个远程API,这个远程API需要传递一个鉴权信息,我们可以把cooki ...

  8. 【spring cloud】spring cloud 使用feign调用,1.fallback熔断器不起作用,2.启动报错Caused by: java.lang.ClassNotFoundException: com.netflix.hystrix.contrib.javanica.aop.aspectj.Hystri解决

    示例GitHub源码地址:https://github.com/AngelSXD/springcloud 1.首先使用feign调用,需要配置熔断器 2.配置熔断器需要将熔断器注入Bean,熔断器类上 ...

  9. feign调用过程注意事项

    Feign是Netflix开发的声明式.模板化的HTTP客户端, Feign可以帮助我们更快捷.优雅地调用HTTP API. 在Spring Cloud中,使用Feign非常简单——创建一个接口,并在 ...

  10. 跟我学SpringCloud | 第三篇:服务的提供与Feign调用

    跟我学SpringCloud | 第三篇:服务的提供与Feign调用 上一篇,我们介绍了注册中心的搭建,包括集群环境吓注册中心的搭建,这篇文章介绍一下如何使用注册中心,创建一个服务的提供者,使用一个简 ...

随机推荐

  1. 5.pygame快速入门-精灵和精灵组

    在之前案例中,图像加载.位置变化.绘制图像都需要编写代码分别处理 pygame提供了两个类简化开发步骤 pygame.sprite.Sprite #精灵,存储图像数据image和位置rect的对象 p ...

  2. VS使用正则表达式删除程序中的空行

    Ctrl+H; 需要替换的正则表达式 ^(?([^\r\n])\s)*\r?$\r?\n

  3. 二、Celery执行一步任务

    二.Celery执行异步任务 2.1.基本使用 创建项目celerypro 创建异步任务执行文件celery_task: import celery import time backend='redi ...

  4. 三十二、kubernetes集群的网络实现

    Kubernetes集群的网络实现 CNI介绍及集群网络选型 容器网络接口(Container Network Interface),实现kubernetes集群的Pod网络通信及管理.包括: CNI ...

  5. pod(八):pod的调度——将 Pod 指派给节点

    目录 一.系统环境 二.前言 三.pod的调度 3.1 pod的调度概述 3.2 pod自动调度 3.2.1 创建3个主机端口为80的pod 3.3 使用nodeName 字段指定pod运行在哪个节点 ...

  6. 嵌入式-C语言基础:二维数组的地址写法

    二维数组a的有关指针: 表示形式                                含义                                                   ...

  7. 读Bilgin Ibryam 新作 《Dapr 是一种10倍数 平台》

    Bilgin Ibryam 最近加入了开发者软件初创公司Diagrid Inc,他是Apache Software Foundation 的 committer 和成员.他也是一个开源的布道师,并且是 ...

  8. python小练习:涉及print,json,numpy

    枚举参考文件夹中的文件,并与待比较文件件中的同名文件比较是否一致. #! /usr/bin/python3.6 # -*- coding:utf-8 -*- import os import sys ...

  9. .net 温故知新:【10】.NET ORM框架EFCore使用入门之CodeFirs、DBFirst

    前言:本系列是我自己学习.net相关知识,以便跟上.net跨平台的步伐,目前工作原因基本在.net Framework4.7以下,所以才有了这一系列的学习总结,但是并不是从基本的C#语法和基础知识开始 ...

  10. 第三十节:fillder抓取APP数据之小程序

    1.下载fillder ,fillder官网:https://www.telerik.com/fiddler 2.安装好后设置fillder: 工具->选项,打开设置面板.选择HTTPS选项卡. ...