全局异常处理器详解
什么是全局异常处理器?
全局异常处理器是Spring框架提供的统一异常处理机制,用于集中处理应用程序中所有控制器(Controller)层抛出的异常。它的核心价值在于:
- 统一异常处理:避免在每个Controller方法中重复编写try-catch
- 标准化错误响应:确保所有异常返回一致的错误格式
- 解耦业务逻辑:将错误处理与业务代码分离
- 提高可维护性:所有异常处理逻辑集中管理
- 增强安全性:防止敏感异常信息泄露给客户端
核心实现方式
1. 使用 @ControllerAdvice
+ @ExceptionHandler
(推荐)
@RestControllerAdvice // 组合了@ControllerAdvice和@ResponseBody
public class GlobalExceptionHandler {// 处理自定义业务异常@ExceptionHandler(BusinessException.class)public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {ErrorResponse error = new ErrorResponse(ex.getErrorCode(),ex.getMessage(),System.currentTimeMillis());return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);}// 处理参数校验异常@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {List<String> errors = ex.getBindingResult().getFieldErrors().stream().map(error -> error.getField() + ": " + error.getDefaultMessage()).collect(Collectors.toList());ErrorResponse error = new ErrorResponse("VALIDATION_FAILED","参数校验失败",errors,System.currentTimeMillis());return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);}// 处理认证授权异常@ExceptionHandler(AccessDeniedException.class)public ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException ex) {ErrorResponse error = new ErrorResponse("UNAUTHORIZED","无访问权限",System.currentTimeMillis());return new ResponseEntity<>(error, HttpStatus.FORBIDDEN);}// 处理所有未捕获的异常@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 生产环境应隐藏详细错误信息String message = "生产环境".equals(env) ? "服务器内部错误" : ex.getMessage();ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR",message,System.currentTimeMillis());log.error("未处理异常: ", ex);return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);}
}
2. 错误响应体结构(标准化)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {private String code; // 错误码private String message; // 用户友好消息private Object details; // 错误详情(可选)private long timestamp; // 时间戳// 用于校验错误的构造器public ErrorResponse(String code, String message, Object details, long timestamp) {this.code = code;this.message = message;this.details = details;this.timestamp = timestamp;}
}
企业级最佳实践
1. 异常分类处理策略
异常类型 | HTTP状态码 | 处理方式 |
---|---|---|
业务逻辑异常 | 400 | 返回具体错误码和用户友好消息 |
参数校验异常 | 400 | 返回具体字段错误信息 |
认证失败异常 | 401 | 返回认证失败提示 |
权限不足异常 | 403 | 返回权限不足提示 |
资源不存在异常 | 404 | 返回资源不存在提示 |
系统内部异常 | 500 | 返回通用错误(生产环境屏蔽细节) |
服务不可用异常 | 503 | 返回服务维护提示 |
2. 自定义业务异常体系
// 基础业务异常
public class BusinessException extends RuntimeException {private final String errorCode;public BusinessException(String errorCode, String message) {super(message);this.errorCode = errorCode;}public String getErrorCode() {return errorCode;}
}// 具体业务异常
public class UserNotFoundException extends BusinessException {public UserNotFoundException(Long userId) {super("USER_NOT_FOUND", "用户不存在: " + userId);}
}public class InsufficientBalanceException extends BusinessException {public InsufficientBalanceException(BigDecimal balance) {super("INSUFFICIENT_BALANCE", "余额不足,当前余额: " + balance);}
}
3. 自动处理参数校验
结合 @Valid
注解自动捕获校验异常:
@PostMapping("/users")
public UserDTO createUser(@Valid @RequestBody CreateUserRequest request) {// 业务逻辑
}// 在全局异常处理器中
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {// 提取所有字段错误Map<String, String> errors = ex.getBindingResult().getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField,fieldError -> fieldError.getDefaultMessage() != null ? fieldError.getDefaultMessage() : ""));return ResponseEntity.badRequest().body(new ErrorResponse("VALIDATION_ERROR", "参数校验失败", errors));
}
4. 生产环境安全处理
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 区分开发和生产环境String errorMessage = "系统错误";// 开发环境显示详细错误if ("dev".equals(environment.getProperty("spring.profiles.active"))) {errorMessage = ex.getMessage();}// 记录完整错误日志log.error("未处理异常: ", ex);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("SERVER_ERROR", errorMessage));
}
高级功能扩展
1. 异常国际化支持
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex, HttpServletRequest request) {// 从请求头获取语言String language = request.getHeader("Accept-Language");Locale locale = StringUtils.hasText(language) ? Locale.forLanguageTag(language) : Locale.getDefault();// 使用MessageSource获取本地化消息String localizedMessage = messageSource.getMessage(ex.getErrorCode(), new Object[]{}, ex.getMessage(), // 默认消息locale);return ResponseEntity.badRequest().body(new ErrorResponse(ex.getErrorCode(), localizedMessage));
}
2. 异常监控集成
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 发送异常到监控系统metricsService.recordException(ex);// 发送告警通知if (ex instanceof CriticalException) {alertService.sendCriticalAlert(ex);}// ... 其他处理
}
3. 自定义异常处理器顺序
@Order(Ordered.HIGHEST_PRECEDENCE) // 最高优先级
@RestControllerAdvice
public class SecurityExceptionHandler {@ExceptionHandler(AuthenticationException.class)public ResponseEntity<ErrorResponse> handleAuthException(AuthenticationException ex) {// 特殊处理认证异常}
}@Order(Ordered.LOWEST_PRECEDENCE) // 最低优先级
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {// 兜底处理}
}
使用场景示例
Controller中的使用
@RestController
@RequestMapping("/api/orders")
public class OrderController {@PostMappingpublic ResponseEntity<OrderDTO> createOrder(@Valid @RequestBody CreateOrderRequest request) {// 业务代码无需处理异常OrderDTO order = orderService.createOrder(request);return ResponseEntity.ok(order);}@GetMapping("/{id}")public ResponseEntity<OrderDTO> getOrder(@PathVariable Long id) {// 直接抛出业务异常OrderDTO order = orderService.getOrder(id).orElseThrow(() -> new OrderNotFoundException(id));return ResponseEntity.ok(order);}
}
最佳实践总结
-
分层处理:
- 业务层抛出有含义的异常
- 控制器层不处理异常
- 全局处理器统一转换异常为响应
-
标准化响应:
- 统一错误响应格式
- 包含错误码、消息和时间戳
- 必要时添加错误详情
-
异常分类:
- 为不同类型异常创建处理器
- 使用HTTP状态码合理映射业务异常
-
安全考虑:
- 生产环境屏蔽敏感异常信息
- 开发环境显示详细错误
-
监控集成:
- 记录异常日志
- 集成监控告警系统
-
可扩展性:
- 使用自定义异常体系
- 支持异常国际化
全局异常处理器是构建健壮REST API的关键组件,它能显著提高代码质量、增强系统稳定性,并为客户端提供一致的错误处理体验。