题目
设计一个安全的异常处理框架组件
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
自定义异常设计,异常传递与封装,资源清理(try-with-resources),异常日志记录,性能考量
快速回答
设计安全异常处理框架的核心要点:
- 创建分层自定义异常体系(业务异常/系统异常)
- 使用异常包装模式保留原始堆栈
- 结合try-with-resources确保资源释放
- 实现上下文感知的日志记录(含线程/请求ID)
- 通过异常过滤避免敏感信息泄露
- 使用性能友好的异常创建模式
1. 核心设计原理
安全的异常处理框架需要解决:
- 异常分类:区分业务异常(可恢复)和系统异常(需干预)
- 上下文保留:通过cause chain保留原始异常堆栈
- 资源安全:确保文件/网络连接等资源在任何异常场景下都能释放
- 信息控制:避免敏感数据(如SQL、密钥)泄露到日志或前端
2. 代码实现示例
// 1. 自定义异常体系
public abstract class AppException extends Exception {
private final ErrorCode code;
public AppException(ErrorCode code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
// 业务异常(可恢复)
public class BusinessException extends AppException { /*...*/ }
// 系统异常(严重错误)
public class SystemException extends AppException { /*...*/ }
// 2. 异常处理组件
public class ExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger("SECURE_EXCEPTION");
public void handle(Runnable task) {
try (ResourceContext ctx = new ResourceContext()) {
task.run();
} catch (BusinessException e) {
logWarn(e);
throw new UserFriendlyError(e.getCode(), e.getMessage());
} catch (Exception e) {
logError(filterSensitiveData(e));
throw new SystemException("SYSTEM_FAILURE", "服务不可用", e);
}
}
private void logError(Exception e) {
// 附加请求上下文信息
MDC.put("requestId", RequestContext.getId());
LOG.error("ErrorCode: {} - {}",
((AppException)e).getCode(),
e.getMessage(),
e);
}
private Exception filterSensitiveData(Exception raw) {
// 过滤异常中的敏感信息(如SQL参数)
return new SanitizedException(raw);
}
}
// 3. 资源安全示例
class ResourceContext implements AutoCloseable {
private Connection dbConnection;
public ResourceContext() {
this.dbConnection = Database.openConnection();
}
@Override
public void close() {
// 确保任何情况下都关闭连接
try {
if (dbConnection != null && !dbConnection.isClosed()) {
dbConnection.close();
}
} catch (SQLException e) {
// 记录但不再抛出,避免掩盖原始异常
LOG.warn("Resource close failed", e);
}
}
}3. 最佳实践
- 异常创建优化:在频繁调用的代码中,避免在正常流程创建异常对象(影响性能)
- 日志规范:
- 业务异常记录WARN级别
- 系统异常记录ERROR级别
- 始终包含唯一请求ID便于追踪
- 包装原则:跨层调用时(如DAO→Service),将底层异常(如SQLException)包装为业务异常
4. 常见错误
- ❌ 直接暴露底层异常细节(如SQLException给前端)
- ❌ 在finally块中抛出异常导致原始异常丢失
- ❌ 过度使用printStackTrace()造成日志污染
- ❌ 忽略InterruptedException导致线程中断状态丢失
5. 高级扩展
- 性能优化:
- 对于高频调用方法,预先创建静态异常对象(需谨慎使用)
- 使用异常创建开关(仅在调试模式填充堆栈)
- 异步场景:通过CompletableFuture.exceptionally()处理异步任务异常
- 框架集成:在Spring中通过@ControllerAdvice实现全局异常处理
- 监控对接:将异常事件接入APM系统(如SkyWalking)实现实时告警