在Java框架中,异常处理的最佳时机需结合分层架构设计,确保异常在合适的层级被捕获和处理,避免异常传播失控。以下是具体实践建议:
1. 请求处理层(如Spring MVC控制器)- 职责:处理客户端请求和HTTP协议相关的异常(如404、500)。
- 最佳实践:
使用全局异常处理器(如@RestControllerAdvice)统一捕获未处理的异常,返回友好的错误响应。
示例:@RestControllerAdvicepublic class GlobalExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()); }}
- 关键点:避免在此层处理业务逻辑异常,应将其抛给服务层处理。
2. 服务层(业务逻辑层)- 职责:处理业务规则相关的异常(如数据校验失败、状态冲突)。
- 最佳实践:
通过抛出自定义异常明确错误类型(如UserNotFoundException)。
示例:public class UserService { public User getUserById(Long id) { return userRepository.findById(id) .orElseThrow(() -> new UserNotFoundException("User not found")); }}
- 关键点:服务层异常应包含业务上下文信息,便于上层统一处理。
3. 数据访问层(DAO/Repository)- 职责:处理数据库或外部服务调用的异常(如连接超时、SQL错误)。
- 最佳实践:
捕获底层异常(如SQLException),转换为更具业务意义的异常(如DataAccessException)。
示例:public class UserRepository { public User findById(Long id) { try { return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id=?", userRowMapper, id); } catch (DataAccessException ex) { throw new DatabaseException("Failed to access database", ex); } }}
- 关键点:避免将原始异常(如SQLException)直接抛给上层。
4. 多线程环境- 职责:线程内异常需由线程自身处理,避免因未捕获异常导致线程终止。
- 最佳实践:
使用try-catch块或UncaughtExceptionHandler:Thread thread = new Thread(() -> { try { // 业务代码 } catch (Exception ex) { log.error("Thread error", ex); }});thread.setUncaughtExceptionHandler((t, e) -> log.error("Uncaught in thread", e));
- 关键点:异步任务(如@Async)需通过AsyncUncaughtExceptionHandler处理异常。
5. 通用原则- 分层隔离:低层异常转换为高层可理解的异常(如数据库异常→业务异常→HTTP错误)。
- 避免过度捕获:在可能恢复的场景(如重试逻辑)中捕获异常,否则向上抛出。
- 日志记录:在捕获异常时记录完整堆栈(如log.error("Error details", ex)),但避免在返回给客户端的响应中暴露敏感信息。
实战案例:Spring MVC + Service层协作- Service层抛出业务异常:public class OrderService { public void cancelOrder(Long orderId) throws OrderAlreadyCancelledException { Order order = orderRepository.findById(orderId); if (order.isCancelled()) { throw new OrderAlreadyCancelledException("Order " + orderId + " is already cancelled"); } order.cancel(); }}
- Controller层处理并返回HTTP状态码:@RestControllerpublic class OrderController { @Autowired private OrderService orderService; @DeleteMapping("/orders/{id}") public ResponseEntity<?> cancelOrder(@PathVariable Long id) { try { orderService.cancelOrder(id); return ResponseEntity.ok().build(); } catch (OrderAlreadyCancelledException ex) { return ResponseEntity.status(HttpStatus.CONFLICT).body(ex.getMessage()); } }}
总结- 请求处理层:处理HTTP协议异常,返回客户端友好响应。
- 服务层:抛出业务异常,集中处理业务规则错误。
- 数据访问层:转换底层异常,避免泄露实现细节。
- 多线程:确保异常不静默丢失。
通过分层处理,既能保证代码可维护性,又能提升用户体验和系统稳定性。