当前位置: 首页 > 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.lryc.cn/news/608701.html

相关文章:

  • AD方案(OpenLDAP或微软AD)适配信创存在的不足以及可能优化方案
  • Nvidia Orin DK 刷机CUDA TensorRT+硬盘扩容+ROS+Realsense+OpenCV+Ollama+Yolo11 一站式解决方案
  • CUDA杂记--nvcc使用介绍
  • Elastic 9.1/8.19:默认启用 BBQ,ES|QL 支持跨集群搜索(CCS)正式版,JOINS 正式版,集成 Azure AI Foundry
  • Jupyter Notebook 中高效处理和实时展示来自 OpenCV 和 Pillow 的图像数据探究
  • Jetpack Compose for XR:构建下一代空间UI的完整指南
  • SpringBoot+Vue高校实验室预约管理系统 附带详细运行指导视频
  • 力扣经典算法篇-41-旋转图像(辅助数组法,原地旋转法)
  • RabbitMQ面试精讲 Day 9:优先级队列与惰性队列
  • 昇思学习营-开发版-模型推理和性能优化
  • Android 之 MVP架构
  • Redis+Lua的分布式限流器
  • Python 实例属性与方法命名冲突:一次隐藏的Bug引发的思考
  • Corrosion2靶机
  • NumPy库学习(三):numpy在人工智能数据处理的具体应用及方法
  • PHP入门及数据类型
  • Android 之 WebView与HTML交互
  • 【Django】-7- 实现注册功能
  • 迈向透明人工智能: 可解释性大语言模型研究综述
  • ubuntu24.04安装selenium、edge、msedgedriver
  • 大语言模型的解码策略:贪婪解码与波束搜索
  • 记一次v-if和key错误使用,导致vue2的内存爆炸修复!
  • 音视频学习(五十):音频无损压缩
  • Arrays.asList() add方法报错java.lang.UnsupportedOperationException
  • Apache Shenyu 本地启动及快速入门
  • 【abc417】E - A Path in A Dictionary
  • HTTPS的概念和工作过程
  • Kazam产生.movie.mux后恢复视频为.mp4
  • Transformer模型用于MT信号相关性预测与分析
  • 知识蒸馏 - 基于KL散度的知识蒸馏 HelloWorld 示例 采用PyTorch 内置函数F.kl_div的实现方式