InfrastructureException是RuntimeException子类,用于封装数据库、缓存等基础设施故障,需在仓储层捕获底层异常并显式转换抛出,配合全局处理器返回503/500响应及标准化错误信息。

在Java仓储(Repository)实现中,InfrastructureException 通常用于封装底层基础设施(如数据库、缓存、消息队列)操作失败时的非业务性异常。它不属于业务逻辑异常(如 BusinessException),而是反映技术层问题(连接超时、SQL语法错误、序列化失败等),应由基础设施层捕获并转换后向上抛出。
明确 InfrastructureException 的定位与继承关系
它一般定义为运行时异常(RuntimeException 的子类),避免强制上层处理,同时保持语义清晰:
public class InfrastructureException extends RuntimeException {
public InfrastructureException(String message) {
super(message);
}
public InfrastructureException(String message, Throwable cause) {
super(message, cause);
}
}
不建议直接 throw new RuntimeException("DB error") —— 这会丢失异常分类信息,也不利于统一监控和重试策略。
在仓储实现中捕获并转换底层异常
以 JPA Repository 实现为例,应在具体方法中捕获 PersistenceException、DataAccessException 或 SQLException 等,并包装为 InfrastructureException:
- 使用 Spring Data JPA 时,框架已将 JDBC 异常转为
DataAccessException子类(如JdbcSQLException),可在自定义仓储实现中统一拦截 - 若用 MyBatis,可在
@Mapper接口的代理调用后,通过 AOP 或 try-catch 在仓储实现类中处理PersistenceException - 避免在 DAO 层吞掉异常或只打印日志 —— 必须显式转换并抛出,确保调用方能识别这是基础设施故障
结合具体操作场景示例
例如,在基于 JDBC 的自定义仓储中保存实体:
@Override
public void save(User user) {
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO users (...) VALUES (...)")) {
// 设置参数...
ps.executeUpdate();
} catch (SQLException e) {
throw new InfrastructureException("Failed to persist user due to database error", e);
}
}
再比如 Redis 缓存操作失败:
@Override
public void cacheUser(User user) {
try {
redisTemplate.opsForValue().set("user:" + user.getId(), user);
} catch (RedisConnectionFailureException | SerializationException e) {
throw new InfrastructureException("Failed to cache user: Redis unavailable or serialization error", e);
}
}
配合全局异常处理器统一响应(可选但推荐)
虽然 InfrastructureException 是 unchecked 异常,但在 Web 层可通过 @ControllerAdvice 捕获并返回标准错误响应:
- HTTP 状态码设为 503(Service Unavailable)或 500(Internal Server Error),视具体失败原因而定
- 响应体中包含 traceId、错误码(如 INFRA_DB_CONNECTION_FAILED)、简明提示(不暴露敏感细节)
- 记录完整堆栈到日志系统,便于运维定位基础设施问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











