Невже так можна очікувати, що Spring MVC поводитиметься?
Станом на Spring 4.3.7, ось як поводиться Spring MVC: він використовує HandlerExceptionResolverекземпляри для обробки винятків, виданих методами обробника.
За замовчуванням веб-конфігурація MVC реєструє один HandlerExceptionResolverкомпонент a HandlerExceptionResolverComposite, який
делегатів до списку інших HandlerExceptionResolvers.
Ці інші вирішувачі
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
зареєстровано в такому порядку. Для цілей цього питання ми лише піклуємось ExceptionHandlerExceptionResolver.
Те, AbstractHandlerMethodExceptionResolverщо вирішує винятки за допомогою @ExceptionHandlerметодів.
При ініціалізації контексту Spring генерує ControllerAdviceBeanдля кожного @ControllerAdviceанотованого класу, який виявляє. ExceptionHandlerExceptionResolverБуде витягувати їх з контексту, і сортувати їх , використовуючи при допомоги AnnotationAwareOrderComparatorяких
є розширенням, OrderComparatorяке підтримує Ordered
інтерфейс Spring, а також анотації @Orderand @Priority, зі значенням замовлення, що надається впорядкованим екземпляром, замінюючи статично визначене значення анотації (якщо воно є).
Потім він реєструє ExceptionHandlerMethodResolverдля кожного з цих ControllerAdviceBeanекземплярів (зіставлення доступних @ExceptionHandlerметодів із типами винятків, з якими вони мають працювати). Вони нарешті додаються в тому ж порядку до LinkedHashMap(який зберігає порядок ітерацій).
Коли виникає виняток, ExceptionHandlerExceptionResolverволя перебирає їх ExceptionHandlerMethodResolverі використовує перший, який може обробляти виняток.
Так точки тут: якщо у вас є @ControllerAdviceз @ExceptionHandlerдля Exceptionщо реєструються перед іншим @ControllerAdviceкласом з @ExceptionHandlerдля більш конкретного винятку, як IOException, що перші з них будуть викликатися. Як вже згадувалося раніше, ви можете керувати цим порядком реєстрації, @ControllerAdviceреалізувавши свій анотований клас Orderedабо анотуючи його за допомогою @Orderабо @Priorityі надаючи йому відповідне значення.
@ExceptionHandlerметодів у межах a@ControllerAdvice, вибирається той, який обробляє найбільш конкретний суперклас викинутого винятку.