¿Es así como se esperaría que se comporte Spring MVC?
A partir de Spring 4.3.7, así es como se comporta Spring MVC: usa HandlerExceptionResolver
instancias para manejar excepciones lanzadas por métodos de controlador.
De forma predeterminada, la configuración de MVC web registra un solo HandlerExceptionResolver
bean, a HandlerExceptionResolverComposite
, que
delegados a una lista de otros HandlerExceptionResolvers
.
Esos otros resolutores son
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
registrado en ese orden. A los efectos de esta pregunta solo nos preocupamos ExceptionHandlerExceptionResolver
.
Una AbstractHandlerMethodExceptionResolver
que resuelve excepciones a través de @ExceptionHandler
métodos.
En la inicialización del contexto, Spring generará un ControllerAdviceBean
para cada @ControllerAdvice
clase anotada que detecte. Los ExceptionHandlerExceptionResolver
recuperará del contexto y los ordenará usando el AnnotationAwareOrderComparator
que
es una extensión de OrderComparator
que admite la Ordered
interfaz de Spring, así como las anotaciones @Order
y @Priority
, con un valor de orden proporcionado por una instancia Ordenada que anula un valor de anotación definido estáticamente (si lo hubiera).
Luego registrará un ExceptionHandlerMethodResolver
para cada una de estas ControllerAdviceBean
instancias (mapeando los @ExceptionHandler
métodos disponibles a los tipos de excepción que deben manejar). Estos finalmente se agregan en el mismo orden a a LinkedHashMap
(que conserva el orden de iteración).
Cuando ocurre una excepción, ExceptionHandlerExceptionResolver
iterará a través de estos ExceptionHandlerMethodResolver
y usará el primero que pueda manejar la excepción.
Entonces, el punto aquí es: si tiene una @ControllerAdvice
con una @ExceptionHandler
para, Exception
se registra antes que otra @ControllerAdvice
clase con una @ExceptionHandler
para una excepción más específica, como IOException
, se llamará a la primera. Como se mencionó anteriormente, puede controlar ese orden de registro haciendo que su @ControllerAdvice
clase anotada implemente Ordered
o anotándola con @Order
o @Priority
y dándole un valor apropiado.
@ExceptionHandler
métodos dentro de a@ControllerAdvice
, se elige el que maneja la superclase más específica de la excepción lanzada.