在Web开发中,异常处理是保证系统健壮性的关键环节。但你是否遇到过这样的问题:Controller中每个方法都写try-catch
处理异常,代码冗余且难以维护?Spring MVC提供了一套优雅的机制实现统一异常处理,既能避免代码重复,又能灵活控制异常响应。本文从源码层面解析其实现原理,助你彻底掌握这一核心技能!
一、Spring MVC统一异常处理的核心机制
1. 核心注解:@ControllerAdvice
+ @ExceptionHandler
-
@ControllerAdvice
:标记一个类为全局异常处理器,可拦截所有Controller抛出的异常。 -
@ExceptionHandler
:标记处理特定异常的方法,支持定义多种异常类型。
示例代码:
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理所有NullPointerException
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<String> handleNullPointer(NullPointerException ex) {
return ResponseEntity.status(500).body("空指针异常:" + ex.getMessage());
}
// 处理所有其他异常
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return ResponseEntity.status(500).body("系统错误:" + ex.getMessage());
}
}
二、源码解析:异常处理如何生效?
1. 核心接口:HandlerExceptionResolver
Spring MVC通过HandlerExceptionResolver
接口处理Controller抛出的异常,其核心实现类是ExceptionHandlerExceptionResolver
。
源码入口:DispatcherServlet
的processHandlerException
方法。
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// 遍历所有注册的HandlerExceptionResolver
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
ModelAndView mav = resolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
throw ex;
}
2. @ExceptionHandler
的底层实现
ExceptionHandlerExceptionResolver
负责处理带有@ExceptionHandler
注解的方法。其核心逻辑如下:
-
扫描所有
@ControllerAdvice
类:在应用启动时,通过ExceptionHandlerMethodResolver
收集所有异常处理方法。 -
匹配异常类型:当Controller抛出异常时,根据异常类型找到最匹配的
@ExceptionHandler
方法。 -
反射调用处理方法:通过反射执行对应方法,生成响应结果。
源码片段:
// ExceptionHandlerExceptionResolver 中处理异常
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
// 1. 查找匹配的@ExceptionHandler方法
Method method = getExceptionHandlerMethod(handlerMethod, exception);
// 2. 反射调用方法
Object result = invokeMethod(method, handlerMethod, exception, request, response);
// 3. 处理返回值(如ModelAndView、ResponseEntity等)
return handleResult(request, response, result);
}
3. @ControllerAdvice
的扫描机制
Spring通过ControllerAdviceBean
类扫描所有标注@ControllerAdvice
的类,并在容器启动时注册它们的异常处理方法。
源码关键逻辑:
// ExceptionHandlerExceptionResolver 初始化时加载所有@ControllerAdvice
public void afterPropertiesSet() {
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
for (ControllerAdviceBean adviceBean : adviceBeans) {
// 解析每个@ControllerAdvice类中的@ExceptionHandler方法
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(adviceBean.getBeanType());
this.exceptionHandlerCache.put(adviceBean, resolver);
}
}
三、其他异常处理方式
1. 实现HandlerExceptionResolver
接口
自定义异常解析器,适合需要完全控制异常响应逻辑的场景。
@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
if (ex instanceof CustomException) {
response.setStatus(500);
return new ModelAndView("error/custom"); // 返回自定义错误页面
}
return null; // 其他异常由其他解析器处理
}
}
2. 使用SimpleMappingExceptionResolver
通过配置映射特定异常到错误页面,适合简单场景。
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">error/npe</prop>
</props>
</property>
</bean>
四、最佳实践与避坑指南
1. 异常处理优先级
Spring MVC按以下顺序处理异常:
-
@ExceptionHandler
(当前Controller内) → 2.@ControllerAdvice
→ 3.HandlerExceptionResolver
实现类 → 4. 默认错误页面
避坑:若自定义HandlerExceptionResolver
返回非空结果,会中断后续处理!
2. 异常匹配规则
-
精准匹配:优先匹配抛出异常的具体类型(如
NullPointerException
)。 -
继承链匹配:若未找到具体类型,会向上匹配父类异常(如
RuntimeException
)。
示例:若同时定义@ExceptionHandler(NullPointerException.class)
和@ExceptionHandler(Exception.class)
,抛出NullPointerException
时优先触发前者。
3. 返回值类型支持
@ExceptionHandler
方法支持多种返回值:
-
ModelAndView:返回视图和模型数据。
-
ResponseEntity:灵活控制HTTP状态码和响应体。
-
@ResponseBody:直接返回JSON数据(需配合
@RestControllerAdvice
)。
五、总结
-
核心机制:
@ControllerAdvice
+@ExceptionHandler
是Spring MVC统一异常处理的首选方案,基于ExceptionHandlerExceptionResolver
实现。 -
底层流程:DispatcherServlet捕获异常 → 遍历HandlerExceptionResolver → 反射调用匹配的@ExceptionHandler方法。
-
灵活扩展:可通过自定义
HandlerExceptionResolver
或SimpleMappingExceptionResolver
满足不同需求。