Spring ControllerAdvice未按预期捕获异常问题咨询
嘿,我来帮你排查这个问题——这种情况我碰到过好多次,大概率是这几个常见原因导致的,咱们一个个捋:
1. 异常发生在DispatcherServlet的请求处理生命周期之外
@ControllerAdvice 搭配 @ExceptionHandler 只能捕获**控制器层(包括@RequestMapping方法、@RestController等)**以及Spring MVC拦截器(HandlerInterceptor)抛出的异常。如果异常是在这些环节之外发生的,比如:
- 请求到达DispatcherServlet之前(比如Tomcat的Filter过滤器里)
- DispatcherServlet初始化阶段
- 请求处理完成后的后续异步流程里
那全局异常处理器根本没机会接触到这些异常,自然抓不到。这种情况得针对性处理,比如Filter里的异常要在Filter里自己处理,或者配置容器级的错误页面。
2. @ControllerAdvice的扫描范围没覆盖异常抛出的组件
看你贴的代码,@ControllerAdvice没指定扫描范围,默认只会扫描当前类所在包及其子包下的控制器。如果抛出异常的控制器不在这个范围内,那这个全局处理器就不会生效。你可以手动指定扫描范围,比如:
@ControllerAdvice(basePackages = "com.yourproject.controllers") public class ExceptionControllerAdvice { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> exceptionHandler(Exception ex) { // 你的处理逻辑 ErrorResponse error = new ErrorResponse(); error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); error.setMessage("Please contact your administrator"); return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); } }
3. 异常被优先级更高的处理器先捕获了
Spring的异常处理器有明确的优先级:
- 控制器内部的
@ExceptionHandler(方法级) > 全局@ControllerAdvice里的处理器 - 内置的异常解析器(比如
ResponseStatusExceptionResolver)也可能先处理某些特定异常
如果抛出异常的控制器里已经有处理Exception.class的@ExceptionHandler方法,那全局的处理器就会被“屏蔽”。你可以检查下目标控制器里有没有这类方法。
4. 异步请求中的异常未被正确处理
如果异常是从@Async注解标记的异步方法里抛出的,@ControllerAdvice默认抓不到——因为异步请求的线程和DispatcherServlet的请求线程不是同一个上下文。这种情况需要自定义AsyncUncaughtExceptionHandler来处理异步方法的异常。
5. Spring MVC的注解驱动未启用
如果你是手动配置Spring MVC(比如用Java配置类),但没加@EnableWebMvc;或者用XML配置时没加<mvc:annotation-driven/>,那Spring不会自动识别@ControllerAdvice这类注解,自然不会注册你的全局异常处理器。一定要确保启用了注解驱动。
快速验证小技巧
你可以在ExceptionControllerAdvice里加个初始化方法,看看这个类有没有被Spring实例化:
@ControllerAdvice public class ExceptionControllerAdvice { @PostConstruct public void init() { System.out.println("ExceptionControllerAdvice initialized!"); } // 你的异常处理方法 }
如果启动后没看到这个日志,说明这个类根本没被Spring扫描到,那优先排查扫描范围或者配置问题。
内容的提问来源于stack exchange,提问作者GionJh

