You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

集成Spring Retry后自定义异常未被全局异常处理器处理如何解决

问题原因

Spring Retry基于AOP实现,标注@Retryable的方法会被动态代理包装,方法抛出的异常会被代理层先处理:哪怕你配置了exclude = MyException.class跳过该异常的重试逻辑,最终向外抛出的异常也会被代理层包装为外层异常(常见如UndeclaredThrowableException、RetryException)。你原有逻辑直接对外层异常做instanceof判断,自然匹配不到被包裹的原始MyException。此外你的全局异常处理器本身也存在定义错误。

解决步骤

1. 修正全局异常处理器的错误定义

你当前的MyExceptionHandler错误继承了RuntimeException,@RestControllerAdvice是异常处理切面类,不需要继承任何异常类,先删除继承逻辑:

// 修正后,移除extends RuntimeException
@RestControllerAdvice
public class MyExceptionHandler {

2. 异常处理前拆包获取原始根因异常

使用Spring自带的工具类拆解代理层的包装异常,拿到真实抛出的业务异常后再做判断:

@ExceptionHandler(RuntimeException.class)
public Object handleError(RuntimeException ex) {
    // 拆包获取根异常
    Throwable actualEx = org.springframework.core.NestedExceptionUtils.getRootCause(ex);
    // 根异常为空时直接使用当前外层异常兜底
    actualEx = actualEx != null ? actualEx : ex;
    if(actualEx instanceof MyException myException){
        System.out.println("Handled");
        // 按业务逻辑返回响应,原方法缺少返回值会触发框架报错
        return Map.of("code", myException.getCode(), "message", myException.getMessage());
    }
    // 其他异常的处理逻辑
    return Map.of("code", "500", "message", "系统内部错误");
}

3. 可选:优化代理配置减少异常包装

如果不想每次处理异常都手动拆包,可以在启动类的@EnableRetry注解上配置使用CGLIB代理,降低异常被额外包装的概率:

@SpringBootApplication
@EnableRetry(proxyTargetClass = true)
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

4. 检查调用链路

确认@Retryable标注的方法抛出的异常没有被上层业务代码手动捕获,需要最终抛到Controller层才能被全局异常处理器捕获。

内容的提问来源于stack exchange,提问作者Makdous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 06:00:02