Spring Boot中@ExceptionHandler优先级疑问及异常拦截冲突解决
Spring Boot @ExceptionHandler 优先级相关问题解答
问题背景
用户实现了如下Spring Boot异常拦截器:
@ControllerAdvice public class RestExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler public ResponseEntity<ApiExceptionDTO> handleDataIntegrityViolationException(DataIntegrityViolationException ex) { // 返回带友好提示信息的ResponseEntity<ApiExceptionDTO> } // ... 其他@ExceptionHandler方法 @ExceptionHandler(Exception.class) public ResponseEntity<ApiExceptionDTO> handleException(Exception ex) { // 返回ResponseEntity<ApiExceptionDTO> } }
用户原本以为@ExceptionHandler(Exception.class)会优先捕获DataIntegrityViolationException,导致专门的处理器失效,但实际正常工作,因此提出两个问题:
- 为何
@ExceptionHandler(Exception.class)未先捕获该异常? - 若
@ExceptionHandler(Exception.class)拦截了本该由其他处理器处理的异常该如何解决?是否仅当其他拦截器中也存在@ExceptionHandler(Exception.class)时才会出现此情况?
使用Spring Boot版本:2.1.9.RELEASE
解答
1. 为何@ExceptionHandler(Exception.class)未先捕获异常?
Spring在匹配@ExceptionHandler处理器时,遵循最具体异常类型优先的规则。DataIntegrityViolationException是Exception的子类,专门针对该异常定义的处理器比通用的Exception处理器更具体,因此Spring会优先选择handleDataIntegrityViolationException来处理该异常,和处理器在类中的定义顺序无关。
2. 通用处理器拦截专属处理器异常的解决方法及场景
同一个@ControllerAdvice类内部不会出现这种问题,因为Spring会自动按异常类型的具体程度排序匹配。出现通用处理器覆盖专属处理器的情况,大多是多个@ControllerAdvice类共存的场景:
- 比如另一个
@ControllerAdvice类中定义了@ExceptionHandler(Exception.class),且该类的加载优先级高于你的RestExceptionHandler,就会导致所有异常先被这个通用处理器拦截。
解决方法:
- 用
@Order注解给@ControllerAdvice类指定优先级,让包含具体异常处理器的类优先级更高(@Order值越小,优先级越高)。例如给RestExceptionHandler添加@Order(1),其他通用处理器所在类设置@Order(10)。 - 尽量将所有异常处理器集中在同一个
@ControllerAdvice类中,避免分散在多个类里,这样Spring能按类型具体度正确匹配。 - 避免在多个
@ControllerAdvice中定义通用的Exception处理器,只在一个类中保留通用处理器,专门处理没有对应专属处理器的异常。
内容的提问来源于stack exchange,提问作者The Prototype
相关产品推荐
相关产品推荐

