Spring RetryTemplate针对特定异常重试陷入无限循环问题求助
问题根源
你的ExceptionClassifierRetryPolicy每次触发异常分类时,都会新建一个SimpleRetryPolicy实例。由于新实例无法共享重试上下文(比如已重试次数),每次判断都会认为是第1次重试,永远达不到5次上限,最终导致无限循环。
解决方案
方案一:复用重试策略实例(修复原方案)
提前初始化SimpleRetryPolicy和NeverRetryPolicy实例,让分类器直接返回已创建的实例,这样重试次数会被正确累计:
private static RetryTemplate setupRetryTemplate() { RetryTemplate template = new RetryTemplate(); // 退避策略保持不变 FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); fixedBackOffPolicy.setBackOffPeriod(300L); template.setBackOffPolicy(fixedBackOffPolicy); // 提前初始化重试策略实例,避免每次新建 SimpleRetryPolicy dataAccessRetryPolicy = new SimpleRetryPolicy(); dataAccessRetryPolicy.setMaxAttempts(5); NeverRetryPolicy neverRetryPolicy = new NeverRetryPolicy(); ExceptionClassifierRetryPolicy retryPolicy = new ExceptionClassifierRetryPolicy(); retryPolicy.setExceptionClassifier(exception -> { if (exception instanceof DataAccessResourceFailureException) { return dataAccessRetryPolicy; // 返回同一个实例,共享重试上下文 } else { return neverRetryPolicy; // 返回同一个实例 } }); template.setRetryPolicy(retryPolicy); return template; }
方案二:改用SimpleRetryPolicy直接配置(更简洁)
无需使用ExceptionClassifierRetryPolicy,直接通过SimpleRetryPolicy指定允许重试的异常类型和次数,逻辑更直观:
private static RetryTemplate setupRetryTemplate() { RetryTemplate template = new RetryTemplate(); // 退避策略保持不变 FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); fixedBackOffPolicy.setBackOffPeriod(300L); template.setBackOffPolicy(fixedBackOffPolicy); // 配置仅对DataAccessResourceFailureException重试5次 Map<Class<? extends Throwable>, Boolean> retryableExceptions = new HashMap<>(); retryableExceptions.put(DataAccessResourceFailureException.class, true); SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy( 5, // 最大重试次数 retryableExceptions, true, // 是否重试该异常的子类(可选,按需调整) true // 是否重试RuntimeException(可选) ); template.setRetryPolicy(retryPolicy); return template; }
额外优化建议
调用代码中,建议直接抛出原异常而非新建异常,保留完整堆栈信息便于调试:
catch (DataAccessResourceFailureException ex) { log.error("Exception DataAccessResourceFailureException : {}", ex.getMessage(), ex); throw ex; // 直接抛出原异常,而非新建 }
内容的提问来源于stack exchange,提问作者Shail Panchal
相关产品推荐
相关产品推荐

