分布式系统调用异常需分类处理:网络层异常(如connectexception)可重试,业务层异常(如400/500)依错误码决策,非受检异常应前置拦截;须精准捕获具体异常、限制重试边界、保障资源释放与可观测性。

分布式系统调用异常不能靠“包一层try-catch”就万事大吉。核心在于区分异常类型、控制重试边界、避免资源泄漏,同时兼顾可观测性和业务语义。
明确异常分类,按策略响应
远程调用可能抛出三类典型异常:
- 网络层异常:如 ConnectException、SocketTimeoutException,属于可重试场景,通常由网络抖动或服务短暂不可达引起
- 业务层异常:如远程返回的 400/500 HTTP 状态码封装成自定义 ServiceException,需结合错误码判断是否重试(例如“库存不足”不重试,“系统繁忙”可重试)
- 非受检运行时异常:如 NullPointerException、IllegalArgumentException,多源于本地参数校验缺失,应前置拦截,而非在 catch 中兜底
精准捕获,拒绝 Exception 通吃
把所有异常都 catch(Exception e) 会掩盖真实问题,也干扰重试逻辑判断:
- 针对 RestTemplate 或 FeignClient 调用,优先捕获具体异常:HttpServerErrorException 处理 5xx,HttpClientErrorException 处理 4xx,ResourceAccessException 捕获连接超时/拒绝等底层异常
- 多个异常类型用独立 catch 块,子类在前、父类在后(如先 catch(ConnectException),再 catch(IOException))
- 不要忽略异常堆栈——记录 e.printStackTrace() 仅用于调试;生产环境必须用日志框架(如 SLF4J)输出完整堆栈 + 上下文(traceId、接口名、入参摘要)
重试不是无脑循环,要加约束
简单 try-catch + while 循环容易引发雪崩。建议用成熟方案(如 Spring Retry)或手动控制:
- 设置最大重试次数(如 3 次)和退避策略(如指数退避:100ms → 300ms → 900ms)
- 仅对确定可恢复的异常重试(如网络超时),对明确失败的业务异常(如“订单已取消”)直接抛出或降级
- 重试期间避免重复提交(如幂等性设计:带唯一 requestId,服务端校验去重)
资源清理与自动释放
调用过程中若涉及流、连接、线程等资源,务必确保释放:
- HTTP 客户端(如 OkHttp、Apache HttpClient)本身管理连接池,无需手动 close,但要注意配置 connectionTimeout 和 readTimeout
- 若使用 InputStream/ResponseEntity.getBody() 等原始流,必须用 try-with-resources 包裹,避免内存泄漏
- 避免在 finally 中 close 可能抛异常的资源(如 response.close() 抛 IOException),否则会覆盖原始异常;可用 Apache Commons 的 IOUtils.closeQuietly() 静默处理
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











