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

Spring Retry @Retryable使用困惑:5xx异常重试与自定义异常实现咨询

现有代码核心问题
  • 异常处理逻辑屏蔽了重试触发源:原方法将所有捕获到的异常统一转换为自定义异常抛出,即使是5xx对应的HttpServerErrorException也会被提前转换,导致@Retryable配置的重试触发条件完全无法被匹配,重试逻辑永远不会执行。
  • @Recover方法签名不符合Spring Retry规范:
    • 返回值与@Retryable修饰的原方法返回值不匹配:原方法返回String,恢复方法定义为void,框架无法将其识别为合法的恢复兜底方法。
    • 缺少原方法入参:恢复方法除了需要接收最终触发重试失败的异常作为第一个参数,后续参数的类型、顺序必须与原方法入参完全一致,原实现未传入原方法的String key参数,无法匹配调用上下文。
  • 异常分支未做区分:没有按需求将5xx异常(需重试)和其他异常(直接抛自定义异常)做分流处理。
调整后的可运行代码
@Retryable(
    value = HttpServerErrorException.class,
    maxAttempts = 3,
    backoff = @Backoff(delay = 3000)
)
public String callToService(String key) {
    String response;
    try {
        response = //assume a service call here
        return response;
    } catch (Exception ex) {
        // 非5xx类异常,直接转换为自定义异常抛出,不触发重试
        if (!(ex instanceof HttpServerErrorException)) {
            throw new customException("some message", ex);
        }
        // 5xx类异常直接透传,交给@Retryable框架触发重试
        throw ex;
    }
}

@Recover
public String retryFailed(HttpServerErrorException ex, String key) {
    // 重试全部耗尽后,统一抛出自定义异常
    throw new customException("服务调用经3次重试仍失败", ex);
}
匹配需求的核心逻辑
  • 重试触发逻辑:@Retryable配置仅对HttpServerErrorException生效,注意 maxAttempts是含首次调用的总尝试次数,配置为3即代表最多执行3次调用,匹配需求要求;配合3秒的退避间隔,符合重试节奏。5xx异常从catch块透传后会被框架感知,自动按规则触发重试。
  • 非重试异常处理:非HttpServerErrorException类型的异常在catch块中直接转换为自定义异常抛出,这类异常不在@Retryable的重试触发范围内,不会执行额外重试,直接向外抛出。注意 自定义异常customException需定义为运行时异常,否则原方法和恢复方法需要额外声明受检异常抛出。
  • 兜底恢复逻辑:当HttpServerErrorException耗尽所有3次尝试后,框架会自动路由到签名完全匹配的@Recover方法(方法第一个参数为触发重试的异常类型、后续参数与原方法入参顺序一致、返回值与原方法匹配),在方法内统一抛出自定义异常完成兜底。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.30 06:27:08