如何使用Spring @Retryable为指定HTTP错误状态码的外部API调用重试
Spring @Retryable 针对指定5xx HTTP状态码重试实现方案
核心逻辑
@Retryable 注解默认基于异常类型触发重试,要实现按指定HTTP状态码重试,仅需从API调用抛出的异常中提取响应状态码,匹配你需要的500/502/503/504四类状态码即可。
方案1:SpEL表达式实现(最简方案)
直接使用@Retryable提供的exceptionExpression属性编写判断逻辑,无需新增自定义类,适配不同的HTTP客户端配置如下:
适配RestTemplate
Spring RestTemplate默认会将5xx响应封装为HttpServerErrorException,注解配置如下:
@Service public class MyService { @Retryable( maxAttempts = 3, exceptionExpression = """ #root instanceof T(org.springframework.web.client.HttpServerErrorException) && {500,502,503,504}.contains(#root.getStatusCode().value()) """, backoff = @Backoff(delay = 100, multiplier = 2) ) public List<String> doCallExternalResource() { // 外部API调用逻辑,例如RestTemplate.exchange(...) } }
适配OpenFeign
OpenFeign调用产生的异常为FeignException,只需修改表达式中的异常类型和状态码获取方式:
@Retryable( maxAttempts = 3, exceptionExpression = "#root instanceof T(feign.FeignException) && {500,502,503,504}.contains(#root.status())", backoff = @Backoff(delay = 100, multiplier = 2) )
方案2:自定义重试策略(适合复杂判断场景)
如果后续需要扩展更复杂的重试规则,可以自定义重试策略实现:
- 编写自定义重试策略类
public class Custom5xxRetryPolicy extends SimpleRetryPolicy { // 需要重试的状态码列表 private static final List<Integer> RETRY_STATUS_CODES = List.of(500, 502, 503, 504); @Override public boolean canRetry(RetryContext context) { Throwable lastError = context.getLastThrowable(); // 仅匹配指定异常和状态码 if (lastError instanceof HttpServerErrorException serverError) { return RETRY_STATUS_CODES.contains(serverError.getStatusCode().value()) && super.canRetry(context); } // 其他异常不重试 return false; } }
- 注册自定义RetryTemplate
@Configuration public class RetryConfig { @Bean public RetryTemplate custom5xxRetryTemplate() { RetryTemplate retryTemplate = new RetryTemplate(); // 绑定自定义重试策略 retryTemplate.setRetryPolicy(new Custom5xxRetryPolicy()); // 配置退避策略 ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy(); backOffPolicy.setInitialInterval(100); backOffPolicy.setMultiplier(2); retryTemplate.setBackOffPolicy(backOffPolicy); return retryTemplate; } }
- 业务方法绑定自定义RetryTemplate
@Service public class MyService { @Retryable(retryTemplate = "custom5xxRetryTemplate") public List<String> doCallExternalResource() { // 外部API调用逻辑 } }
注意事项
- 必须在启动类或配置类上添加
@EnableRetry注解,否则@Retryable不会生效 - 被
@Retryable注解的方法不能被同一个类的其他方法内部调用,否则AOP切面不生效
内容的提问来源于stack exchange,提问作者Joy
相关产品推荐
相关产品推荐

