当前位置: 首页 > 科技观察

对于可重试的Feign调用,这可能是一个优秀的解决方案

时间:2023-03-16 22:17:14 科技观察

前言在我们公司,不同服务之间通过Feign进行远程调用。框架本身可以配置自己的重试机制,但它是一刀切的做法,所有的调用都是同一个机制,没有办法像我们希望的那样在每个方法的基础上配置它。不过在项目中探索了一种新的写法,通过spring-retry框架集合Feign来实现重试机制,可以为每次调用实现不同的重试机制,那么具体怎么做呢,继续往下看。为了解决上述问题,自定义注解@FeignRetry允许Feign调用的各个接口分别配置不同的重试机制。我们使用了面向方面的编程,写了一个自定义注解:@FeignRetry。此注释的工作方式类似于@Retryable的包装器,并与其共享相同的规范以避免混淆。@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public@interfaceFeignRetry{Backoffbackoff()default@Backoff();intmaxAttempt()默认值3;类[]include()default{};}@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfaceBackoff{longdelay()default1000L;;longmaxDelay()默认0L;doublemultiplier()默认0.0D;;}FeignRetryAspect方面处理@FeignRetry注释。Slf4j@Aspect@ComponentpublicclassFeignRetryAspect{@Around("@annotation(FeignRetry)")publicObjectretry(ProceedingJoinPointjoinPoint)throwsThrowable{Methodmethod=getCurrentMethod(joinPoint);FeignRetryfeignRetry=method.getAnnotation(FeignRetry.class);RetryTemplateretryTemplate=newRetryTemplate();retryTemplate.setBackOffPolicy(prepareBackOffPolicy(feignRetry));retryTemplate.setRetryPolicy(prepareSimpleRetryPolicy(feignRetry));//重试returnretryTemplate.execute(arg0->{intretryCount=arg0.getRetryCount();log.info("发送请求方法:{},最大尝试次数:{},延迟:{},重试次数:{}",method.getName(),feignRetry.maxAttempt(),feignRetry.backoff().delay(),retryCount);returnjoinPoint.proceed(joinPoint.getArgs());});私人乙ackOffPolicyprepareBackOffPolicy(FeignRetryfeignRetry){if(feignRetry.backoff().multiplier()!=0){ExponentialBackOffPolicybackOffPolicy=newExponentialBackOffPolicy();backOffPolicy.setInitialInterval(feignRetry.backoff().delay());backOffPolicy.setMaxInterval(feignRetry.backoff().maxDelay());backOffPolicy.setMultiplier(feignRetry.backoff().multiplier());返回backOffPolicy;}else{FixedBackOffPolicyfixedBackOffPolicy=newFixedBackOffPolicy();fixedBackOffPolicy.setBackOffPeriod(feignRetry.backoff().delay());返回fixedBackOffPolicy;}}privateSimpleRetryPolicyprepareSimpleRetryPolicy(FeignRetryfeignRetry){Map,Boolean>policyMap=newHashMap<>();policyMap.put(RetryableException.class,true);//连接被拒绝或超时policyMap.put(ClientException.class,真);//负载均衡不可用(RunTimeException的原因)if(feignRetry.include().length!=0){for(Classt:feignRetry.include()){policyMap.put(t,true);}}returnnewSimpleRetryPolicy(feignRetry.maxAttempt(),policyMap,true);}privateMethodgetCurrentMethod(JoinPointjoinPoint){MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();返回签名。获取方法();}}捕获FeignRetry注解方法,将配置传给SpringRetryTemplate,根据配置调用服务@FeignRetry。使用方法很简单,只需要在FeignClient方法上注解我们要激活重试机制就可以了。自定义切面的用法类似于Spring自带的@Retryable注解。@GetMapping@FeignRetry(maxAttempt=3,backoff=@Backoff(delay=500L))ResponseEntityretrieve1();@GetMapping@FeignRetry(maxAttempt=6,backoff=@Backoff(delay=500L,maxDelay=20000L,multiplier=4))ResponseEntityretrieve2();另外需要在应用类中使用@EnableRetry注解启动重试,比如可以加载SpringBoot的启动类。综上所述,Feign重试其实是一个很常见的场景。在本文中,我们自定义了一个@FeignRetry注解来实现重试机制。不同的Feign接口可以采用不同的重试策略。是不是很方便?现在在您的项目中使用它。