文章目录
本文是Spring MVC九大组件解析系列第六篇,我们将深入探索Spring MVC的异常处理机制,揭开
@ControllerAdvice
和@ExceptionHandler
的实现原理,分析异常解析的责任链模式,并构建统一的异常处理体系。Spring MVC整体设计核心解密参阅:Spring MVC设计精粹:源码级架构解析与实践指南
一、异常处理的核心价值
在Web应用中,优雅的异常处理是保障系统健壮性的关键:
- 用户体验:向用户提供友好的错误提示,而非晦涩的堆栈信息
- 系统可维护性:统一异常格式,便于日志收集和问题排查
- 业务分离:将异常处理逻辑从业务代码中解耦,保持代码整洁
Spring MVC通过HandlerExceptionResolver
组件实现三大核心功能:
- 异常转换:将Java异常转换为统一的错误响应
- 异常分类:根据不同异常类型采取不同处理策略
- 异常恢复:在异常发生后尽可能恢复系统状态
二、核心接口设计
源码位置:org.springframework.web.servlet.HandlerExceptionResolver
核心源码:
设计哲学:通过责任链模式实现异常处理的解耦和扩展。
三、四大内置实现类源码解析
1. ExceptionHandlerExceptionResolver(现代异常处理核心)
源码位置:org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
支持注解:@ExceptionHandler
和@ControllerAdvice
启动阶段:注解扫描与注册
运行时:异常匹配与处理
2. ResponseStatusExceptionResolver(HTTP状态码处理)
源码位置:org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
支持注解:@ResponseStatus
和ResponseStatusException
核心源码:
3. DefaultHandlerExceptionResolver(默认异常转换)
源码位置:org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
主要功能:将Spring MVC内部异常转换为合适的HTTP状态码
核心源码:
4. SimpleMappingExceptionResolver(传统配置方式)
源码位置:org.springframework.web.servlet.handler.SimpleMappingExceptionResolver
主要功能:通过配置文件映射异常到视图
核心源码:
配置示例:
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("java.lang.Exception", "error/generic");
mappings.setProperty("java.io.IOException", "error/io");
resolver.setExceptionMappings(mappings);
resolver.setDefaultErrorView("error/default");
return resolver;
}
四、异常处理的责任链模式
Spring MVC通过责任链模式组织多个ExceptionResolver
:
配置顺序决定了解析优先级:
// 通过Order接口控制解析顺序
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver() {
return new ExceptionHandlerExceptionResolver();
}
@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
return new SimpleMappingExceptionResolver();
}
五、@ControllerAdvice的深层机制
1. 全局异常处理原理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
ErrorResponse error = new ErrorResponse("系统错误", ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
ErrorResponse error = new ErrorResponse("用户不存在", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
2. 异常匹配算法
关键源码:
六、统一异常处理最佳实践
1. 标准化错误响应
// 统一错误响应体
public class ErrorResponse {
private String code; // 错误代码
private String message; // 用户可见消息
private String detail; // 开发调试详情
private long timestamp; // 时间戳
private String path; // 请求路径
// 构造方法等
}
// 异常处理器
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception ex, WebRequest request) {
ErrorResponse error = ErrorResponse.builder()
.code("INTERNAL_ERROR")
.message("系统内部错误")
.detail(ex.getMessage())
.path(request.getDescription(false))
.timestamp(System.currentTimeMillis())
.build();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
2. 业务异常体系设计
// 基础业务异常
public abstract 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);
}
}
// 统一处理业务异常
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
ErrorResponse error = new ErrorResponse(ex.getErrorCode(), ex.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}
3. 参数验证异常处理
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(
MethodArgumentNotValidException ex) {
List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
List<String> errors = fieldErrors.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.toList());
ErrorResponse error = new ErrorResponse("VALIDATION_FAILED", "参数验证失败", errors);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
}
七、生产环境高级配置
1. 异常处理监控
@Component
public class ExceptionMonitoringAspect {
@Autowired
private MeterRegistry meterRegistry;
@AfterThrowing(pointcut = "within(@org.springframework.web.bind.annotation.RestController *)",
throwing = "ex")
public void monitorException(Exception ex) {
// 记录异常指标
meterRegistry.counter("exception.count",
"type", ex.getClass().getSimpleName(),
"handler", "ExceptionHandler")
.increment();
// 发送告警(重要异常)
if (ex instanceof CriticalBusinessException) {
alertService.sendAlert(new ExceptionAlert(ex));
}
}
}
2. 动态异常配置
@Configuration
public class DynamicExceptionConfig {
@Bean
public SimpleMappingExceptionResolver dynamicExceptionResolver() {
DynamicExceptionResolver resolver = new DynamicExceptionResolver();
resolver.setExceptionMappings(loadExceptionMappingsFromDatabase());
resolver.setWarnLogCategory(DynamicExceptionResolver.class.getName());
return resolver;
}
private Properties loadExceptionMappingsFromDatabase() {
// 从数据库加载异常映射配置
Properties mappings = new Properties();
exceptionConfigRepository.findAll().forEach(config ->
mappings.setProperty(config.getExceptionClass(), config.getViewName())
);
return mappings;
}
}
3. 微服务异常传播
// 跨服务异常响应体
public class ServiceErrorResponse {
private String serviceName;
private String traceId;
private ErrorResponse error;
// 构造方法等
}
// 全局异常处理器(微服务版)
@ExceptionHandler(Exception.class)
public ResponseEntity<ServiceErrorResponse> handleMicroserviceException(
Exception ex, HttpServletRequest request) {
// 获取分布式追踪ID
String traceId = (String) request.getAttribute("X-Trace-Id");
ServiceErrorResponse serviceError = new ServiceErrorResponse(
"user-service", traceId, convertToErrorResponse(ex)
);
return ResponseEntity.status(determineHttpStatus(ex))
.header("X-Trace-Id", traceId)
.body(serviceError);
}
八、设计思想总结
- 责任链模式
多个ExceptionResolver组成处理链,各司其职 - 注解驱动
@ExceptionHandler
和@ControllerAdvice
提供声明式异常处理 - 分层处理
从具体异常到通用异常的逐级fallback机制 - 统一抽象
标准化错误响应格式,提升系统可维护性 - 可扩展架构
支持自定义ExceptionResolver满足特殊需求
下一篇预告:
九大组件源码剖析(七):ViewResolver - 视图解析的智慧
我们将深入分析视图解析机制,探索模板引擎集成原理,以及如何实现多视图技术统一抽象。
思考题:在微服务架构下,如何设计跨服务的异常处理适配器,实现异常信息的标准化和跨服务传播?