当前位置: 首页 > news >正文

Spring Boot AOP 优雅实现异常重试机制

Spring Boot AOP 优雅实现异常重试机制

零侵入、可配置、易扩展
通过 自定义注解 + AOP 环绕通知 在任意方法上实现 异常自动重试,支持
重试次数、间隔、异常类型、快速失败 等高级特性。


一、实现效果

@Service
public class RemoteService {@Retryable(retryTimes = 3, interval = 2_000,retryOn = ConnectException.class,fastFailOn = IllegalArgumentException.class)public String call() {// 调用第三方接口return restTemplate.getForObject(url, String.class);}
}
  • 发生异常后自动重试 3 次,每次间隔 2 秒
  • 出现 IllegalArgumentException 立即结束重试
  • 成功后直接返回结果,对业务代码 零侵入

二、核心步骤

1. 引入依赖(Spring Boot 3.x)

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retryable {int retryTimes() default 3;          // 最大重试次数long interval() default 1_000;       // 间隔毫秒Class<? extends Throwable>[] retryOn() default {}; // 需要重试的异常Class<? extends Throwable>[] fastFailOn() default {}; // 立即失败的异常
}

3. AOP 切面(RetryableAspect)

@Slf4j
@Aspect
@Component
public class RetryableAspect {@Around("@annotation(retryable)")public Object around(ProceedingJoinPoint pjp, Retryable retryable) throws Throwable {int maxAttempts = retryable.retryTimes();long interval    = retryable.interval();Set<Class<?>> retrySet   = Set.of(retryable.retryOn());Set<Class<?>> failSet    = Set.of(retryable.fastFailOn());Throwable lastEx = null;for (int attempt = 1; attempt <= maxAttempts; attempt++) {try {return pjp.proceed();} catch (Throwable ex) {lastEx = ex;// 快速失败if (failSet.stream().anyMatch(c -> c.isAssignableFrom(ex.getClass()))) {log.error("Fast fail on {}", ex.getClass().getSimpleName());throw ex;}// 最后一轮不再重试if (attempt == maxAttempts) {log.error("Exhausted {} attempts", maxAttempts);throw ex;}// 匹配重试异常if (retrySet.isEmpty() || retrySet.stream().anyMatch(c -> c.isAssignableFrom(ex.getClass()))) {log.warn("Retry {}/{} after {}ms caused by {}", attempt, maxAttempts, interval, ex.toString());Thread.sleep(interval);} else {throw ex;}}}throw new IllegalStateException("Should never reach here", lastEx);}
}

4. 在启动类开启 AOP

@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

三、高级扩展(可选)

特性实现方式
指数退避interval 改为 (long) (interval * Math.pow(2, attempt-1))
重试日志追踪利用 MDC 注入 traceId,方便链路追踪
异步重试Thread.sleep 换成 CompletableFuture.delayedExecutor
Spring Retry 集成使用 @EnableRetry + @Retryable(开箱即用,但缺少自定义策略)

四、测试用例

@SpringBootTest
class RetryableTest {@Autowired RemoteService service;@Testvoid shouldRetryAndFinallySuccess() {// 第 1 次失败,第 2 次成功String result = service.call();assertThat(result).isEqualTo("success");}
}

五、一句话总结

一个注解 + 一个切面 = 零侵入、可配置、易维护的异常重试机制
网络抖动、偶发异常 不再影响业务稳定性,真正做到 优雅重试

http://www.dtcms.com/a/313479.html

相关文章:

  • 多线程异步日志系统与实现及 TCP/IP C/S 模型
  • IO流-字节流-FileOutputStream
  • day50预训练模型 CBAM注意力
  • Effective C++ 条款20:宁以pass-by-reference-to-const替换pass-by-value
  • LeetCode 2122.还原原数组
  • centos7安装桌面客户软件并远程连接
  • 学习笔记《区块链技术与应用》第五天 分叉
  • Matlab 高斯牛顿法拟合曲线
  • 力扣-200.岛屿数量
  • 01数据结构-二叉搜索树
  • PAT 甲级题目讲解:1012《The Best Rank》
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-55,(知识点:STM32,外设及其特点)
  • 力扣-124.二叉树中的最大路径和
  • LLM调研
  • 计算用户日活:从数据设计到可视化的全流程(高频场景题)
  • 秋招笔记-8.3
  • AUTOSAR进阶图解==>AUTOSAR_RS_SystemTemplate
  • 元宇宙三维化会给游戏行业带来哪些改变?
  • 什么是列存储(Columnar Storage)?深度解析其原理与应用场景
  • 常见的深度学习模块/操作中的维度约定(系统性总结)
  • io_cancel系统调用及示例
  • e2studio开发RA4M2(6)----GPIO外部中断(IRQ)配置
  • 算法题(181):最大直方矩形面积
  • datasets库 的map方法num_proc=16并行踩坑
  • Java 中的 final 关键字有哪些用法?
  • C++ 虚函数相关问题 **
  • 基于云模型的模糊综合风险评估Matlab代码
  • 网关与路由器的区别
  • access系统调用及示例
  • 延迟任务方案-DelayQueue