前言
场景分析:微信支付后,回调通知o消息通知等处理业务,难免受网络波动造成的延迟。一般解决方案使用try/catch、while循环等进行相关处理,要多写很多代码,代码质量不整洁。于是就有了spring提供的重试模块—— @Retryable,在不入侵原有业务逻辑代码的方式下,优雅的实现重试机制功能。
@Retryable是什么?
spring系列的 spring-retry 是另一个实用程序模块,可以帮助我们以标准方式处理任何特定操作的重试。在
spring-retry 中,所有配置都是基于简单注释的。
@Retryable注解可以注解于方法上,来实现方法的重试机制。
使用步骤
1.pom引入依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2.启用@Retryable
在项目启动类上加上注解 @EnableRetry
@SpringBootApplication
@EnableRetry
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3.方法上添加@Retryable注解
在service的实现类对应上要使用的方法上添加 @Retryable注解
/*
* 根据订单号查询视频会议id,最大默认重试次数三次,延迟时间1秒
*/
@Override
@Retryable(value = BusinessException.class,maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 0))
public Map getVideoUnionMeetingId(String orderSn) throws BusinessException{
Long unionMeetingId = apUnionMeetingRepository.getIdByOrderSn(orderSn);
if(unionMeetingId == null){
throw new BusinessException(BaseExceptionCodes.VIDEO_UNION_MEETING_ID_NOT_GET);
}
HashMap<String, Long> map = new HashMap<>();
map.put("unionMeetingId",unionMeetingId);
return map;
}
在同一个实现类下加上回调方法
@Recover(如果不需要回调方法,可以直接不写回调方法),实现的效果是,重试次数完了后,如果还是没成功没符合业务判断,就抛出异常
/**
* 回调方法
* @return
*/
@Recover
public Map recover(BusinessException e) {
System.out.println("---未找到对应的视频号ID----");
HashMap<String, Long> map = new HashMap<>();
map.put("unionMeetingId",null);
return map;
}
4.调用API测试
ApiPost调用返回结果
{
"code": 0,
"msg": "成功",
"message": "成功",
"data": [
{
"unionMeetingId": null
}
],
"timestamp": "2022-09-15 11:34:03"
}
方法执行结果输出,重试机制三次,间隔一秒
注意事项
1. @Retryable注解参数
@Retryable(value = BusinessException.class,maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 0))
value:抛出指定异常才会重试
include:和value一样,默认为空,当exclude也为空时,默认所有异常
exclude:指定不处理的异常
maxAttempts:最大重试次数,默认3次
backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000L,我们设置为2000L;
multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。
2. 注意事项:
1-由于是基于AOP实现,所以不支持类里自调用方法
2-如果重试失败需要给@Recover注解的方法做后续处理,那这个重试的方法不能有返回值,只能是void
方法内不能使用try catch,只能往外抛异常
3-@Recover注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。
4-重试如何实现的?使用spring AOP实现,底层封装为一个while循环并catch住异常,然后根据配置判断是否需要继续重试
优雅,永不过时
@Retryable 主要的适用场景为在调用第三方服务的接口时。由于会出现网络抖动等一些意外的情况这时候重试机制就会适合使用。