Smalldok's Tech Blog

穷则变、变则通、通则达


  • 首页

  • 分类

  • 关于

  • 标签

  • 归档

  • 公益 404

  • 搜索

spring-retry 破坑

| 分类于 服务治理 | 评论数: | 阅读次数:

使用场景

A接口 -> B接口 调用失败,重试、重试失败降级处理;
如:实现第三方的app Push推送;
如:消息系统推送消息给订阅方;

pom.xml

项目基于springboot,在根pom.xml中引用,所以这里没有<version>,以springboot中的版本为准;
项目根pom.xml

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
<relativePath/>
</parent>

项目modepom.xml

1
2
3
4
5
6
7
8
9
<!-- spring-retry -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>

spring-retry知识

1
2
3
4
5
6
@Retryable(value= {RemoteAccessException.class},maxAttempts = 3,backoff = @Backoff(delay = 1000l,multiplier = 1))
public void call(String param){
}
@Recover
public void recover(RemoteAccessException e) {
}
  • @Retryable
    value选择需要重试的异常,可指定多个;
    maxAttempts 最大重试次数,超过则调用@Recover指定的方法(根据异常类型)
    delay 每次重试的间隔时间
  • @Recover
    当超过重试次数,则调用此注解的方法(根据异常类型)

使用原则:不要全部异常都进行重试,要有选择性的根据异常重试;

两种使用方式

我目前使用的第一种方式,因为业务比较简单;

1、@Retryable和@Recover在同一个类中

@EnableRetry启动配置

1
2
3
4
@Configuration
@EnableRetry
class RetryConfig{
}

业务类RemoteService.java

1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class RemoteService {
@Retryable(value= {RemoteAccessException.class},maxAttempts = 3,backoff = @Backoff(delay = 1000l,multiplier = 1))
public void call(String param){
System.out.println("do something...");
throw new RemoteAccessException("RPC调用异常");
}
@Recover
public void recover(RemoteAccessException e) {
System.out.println("recover====>"+e.getMessage());
}
}

约束:
1、@Retryable 和 @Recover必须在同一个类中
2、这个类必须是受spring管理的bean
3、方法必须是public

2、拦截器

@EnableRetry启动配置,且加上拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@ConditionalOnProperty(prefix = "mq.consumer.callback", name = {"retry-times","retry-delay-inMilliseconds"} ,matchIfMissing = false)
@EnableRetry
public class RetryConfig{
@Autowired
private ConsumerProperties consumerProperties;

//每一个业务方法对应一个拦截器和自定义recover
@Bean
@ConditionalOnMissingBean(name = "retryInterceptor")
public RetryOperationsInterceptor retryInterceptor() {
return RetryInterceptorBuilder
.stateless().recoverer(new CustomMessageRecover())
.backOffOptions(0L,1D, consumerProperties.getCallback().getRetryDelayInMilliseconds())
.maxAttempts(consumerProperties.getCallback().getRetryTimes()).build();
}
static class CustomMessageRecover implements MethodInvocationRecoverer<Void> {
@Override
public Void recover(Object[] args, Throwable cause) {
System.out.println("IN THE RECOVER ZONE!!!");
return null;
}
}
}

业务类RemoteService.java

1
2
3
4
5
6
7
8
@Service
public class RemoteService {
@Retryable(value= {RemoteAccessException.class},interceptor = "retryInterceptor")
public void call(String param){
System.out.println("do something...");
throw new RemoteAccessException("RPC调用异常");
}
}

注意到没?@Recover注解的方法不在里面了;已经由拦截器代理到CustomMessageRecover类

1…8910…100
smalldok

smalldok

JAVA服务端架构,目前方向是微服务落地、基础设施、中间件、DevOps

100 日志
27 分类
17 标签
Links
  • sofa-bolt
  • sofa-rpc
  • dubbo
  • sofa-tracer
  • sofa-boot
  • Sentinel
  • COLA
  • nacos
  • xxl-job
  • apollo
  • sharding-sphere
  • fescar
  • ByteTCC
  • tcc-transaction
  • rocketmq
  • canal
  • arthas
  • jvm-sandbox
  • sofa-lookout
  • disruptor
  • mpush
© 2007 – 2019 smalldok
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Mist v6.7.0