@ExceptionHandler 默认无法拦截 Aspect(切面)中抛出的异常
@ExceptionHandler 默认无法拦截 Aspect(切面)中抛出的异常
原因
Spring 的 @ExceptionHandler 是通过 DispatcherServlet 和 @ControllerAdvice 处理的,属于 MVC 层的异常处理。但 Aspect(切面)的代码是在 代理对象 中执行的,它的异常会先于 Controller 方法抛出,导致 @ExceptionHandler 无法捕获。
- 如果异常是从 @Aspect 类抛出的,它会直接绕过 DispatcherServlet 的异常处理机制。
- @ExceptionHandler 只能处理 Controller 方法内部 或 Filter/Interceptor 层 抛出的异常。
解决方案
原则
:
场景 | 异常处理方式 |
---|---|
Aspect 直接抛出异常 | 需在 Aspect 内部处理 |
Controller 方法抛出异常 | @ExceptionHandler 可以捕获 |
Filter/Interceptor 抛出异常 | 需通过 @ControllerAdvice 处理 |
-
在 Aspect 内部直接捕获并处理异常
-
重新抛出异常,让 Controller 层处理,最终由 @ExceptionHandler 处理
-
如果异常是从 Controller 方法内部抛出的(但经过 Aspect 增强),可以通过 @Order 控制执行顺序:
@ControllerAdvice @Order(Ordered.HIGHEST_PRECEDENCE) // 确保优先级高于 AOP 切面 public class GlobalExceptionHandler { }
结论
- 如果异常是从 Aspect 直接抛出的:优先在 Aspect 内部处理。
- 如果异常是从 Controller 方法抛出的:确保 @ExceptionHandler 或 @ControllerAdvice 能覆盖到。
- 调整执行顺序:通过 @Order 控制切面和异常处理的优先级。