应只对目标异常(如sockettimeoutexception)重试,通过retryifexceptionoftype指定类型;配置指数退避(basedelay=100ms、multiplier=2、maxattempts=4–6),由retryer自动执行重试逻辑,避免手动while+try-catch。

可以利用 try-catch 捕获特定异常,结合 Retryer(如 Guava 或 Resilience4j 提供的重试器)配置指数退避策略,实现只对目标异常重试、失败后按 2ⁿ 延迟递增重试的逻辑。
明确重试边界:只对指定异常类型触发重试
Retryer 的核心是“条件化重试”,不是所有异常都该重试。例如网络超时(SocketTimeoutException)、服务暂时不可用(ConnectException)适合重试;而参数错误(IllegalArgumentException)或数据不存在(NotFoundException)通常应立即失败。
- 使用 retryIfExceptionOfType() 显式声明需重试的异常类,避免泛型捕获
Exception - 若需组合多个异常类型,可用 retryIfException() 配合 lambda 判断
e instanceof XxxException - 注意子类继承关系——注册
IOException.class会覆盖其所有子类(如TimeoutException),但不会匹配RuntimeException
配置指数退避:设置 baseDelay、multiplier 和 maxAttempts
指数退避指每次重试间隔按固定倍数增长(如 100ms → 200ms → 400ms → 800ms),防止雪崩并给系统恢复时间。关键参数含义:
- baseDelay:首次重试前等待毫秒数(如 100)
- multiplier:退避倍率(通常为 2.0)
- maxAttempts:最大尝试次数(含首次调用,建议设为 4–6)
- 可选加 jitter(随机扰动)避免重试洪峰,如 Resilience4j 支持
RandomJitter
与 try-catch 协同:不手动吞异常,让 Retryer 主导流程
不要在业务代码里自己写 while + try-catch 实现重试——这容易绕过 Retryer 的退避、熔断、监控等能力。正确做法是:
- 把可能抛出目标异常的调用封装为一个 Callable 或 Supplier
- 将该函数传给 Retryer.execute(),由它内部完成捕获、判断、延迟、重试
- 外部 try-catch 仅用于兜底处理最终失败(如记录告警、返回默认值),而非控制重试逻辑
- 示例:
retryer.call(() -> httpClient.doPost(url, data)),异常由 retryer 自动识别并响应
验证与调试:关注重试日志和实际触发时机
重试是否真正按预期工作,不能只看代码配置。需确认:
- 日志中是否出现多次“Retrying...”提示(如 Guava Retryer 默认输出到 FINE 级别)
- 两次调用之间的时间间隔是否符合 100ms → 200ms → 400ms 规律(可用 System.nanoTime() 打点验证)
- 非目标异常(如 NPE)是否未触发重试,而是直接抛出
- 达到 maxAttempts 后是否抛出 RetryException(Guava)或 RetryException 包装的原始异常(Resilience4j)
不复杂但容易忽略的是异常类型的精确匹配和退避参数的合理性。配错一个 class 或少设一次 maxAttempts,就可能导致无限重试或完全不重试。











