Это то, как можно ожидать поведения Spring MVC?
Начиная с Spring 4.3.7, Spring MVC ведет себя следующим образом: он использует HandlerExceptionResolver
экземпляры для обработки исключений, генерируемых методами обработчика.
По умолчанию конфигурация веб-MVC регистрирует один HandlerExceptionResolver
bean-компонент a HandlerExceptionResolverComposite
, который
делегаты к списку других HandlerExceptionResolvers
.
Остальные резолверы
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
зарегистрированы в таком порядке. Мы заботимся только об этом вопросе ExceptionHandlerExceptionResolver
.
Объект, AbstractHandlerMethodExceptionResolver
который разрешает исключения с помощью @ExceptionHandler
методов.
При инициализации контекста Spring будет генерировать a ControllerAdviceBean
для каждого @ControllerAdvice
обнаруженного аннотированного класса. Они ExceptionHandlerExceptionResolver
будут извлекать их из контекста и сортировать их, используя AnnotationAwareOrderComparator
which
является расширением , OrderComparator
которое поддерживает в Spring Ordered
интерфейс, а также @Order
и @Priority
аннотаций, со значением порядка , предоставленной упорядоченном например Переопределение статически определенное значение аннотаций (если таковые имеются).
Затем он зарегистрирует ExceptionHandlerMethodResolver
для каждого из этих ControllerAdviceBean
экземпляров (сопоставив доступные @ExceptionHandler
методы с типами исключений, которые они должны обрабатывать). Наконец, они добавляются в том же порядке к LinkedHashMap
(что сохраняет порядок итераций).
Когда возникает исключение, он ExceptionHandlerExceptionResolver
будет перебирать их ExceptionHandlerMethodResolver
и использовать первый, который может обработать исключение.
Итак, суть в следующем: если у вас есть объект @ControllerAdvice
с @ExceptionHandler
for, Exception
который регистрируется перед другим @ControllerAdvice
классом с @ExceptionHandler
более конкретным исключением, например IOException
, будет вызван первый класс . Как упоминалось ранее, вы можете управлять этим порядком регистрации, @ControllerAdvice
реализуя свой аннотированный класс Ordered
или аннотируя его с помощью @Order
или @Priority
и давая ему соответствующее значение.
@ExceptionHandler
методов в a@ControllerAdvice
выбирается тот, который обрабатывает наиболее конкретный суперкласс созданного исключения.Сотириос Делиманолис очень помог в своем ответе. При дальнейшем исследовании мы обнаружили, что в весенней версии 3.2.4 в любом случае код, который ищет аннотации @ControllerAdvice, также проверяет наличие аннотаций @Order и сортирует список ControllerAdviceBeans.
Результирующий порядок по умолчанию для всех контроллеров без аннотации @Order - Ordered # LOWEST_PRECEDENCE, что означает, что если у вас есть один контроллер, который должен иметь самый низкий приоритет, то ВСЕ ваши контроллеры должны иметь более высокий порядок.
Вот пример, показывающий, как иметь два класса обработчиков исключений с аннотациями ControllerAdvice и Order, которые могут обслуживать соответствующие ответы при возникновении UserProfileException или RuntimeException.
class UserProfileException extends RuntimeException { } @ControllerAdvice @Order(Ordered.HIGHEST_PRECEDENCE) class UserProfileExceptionHandler { @ExceptionHandler(UserProfileException) @ResponseBody ResponseEntity<ErrorResponse> handleUserProfileException() { .... } } @ControllerAdvice @Order(Ordered.LOWEST_PRECEDENCE) class DefaultExceptionHandler { @ExceptionHandler(RuntimeException) @ResponseBody ResponseEntity<ErrorResponse> handleRuntimeException() { .... } }
Наслаждайтесь!
источник
Порядок обработки исключений можно изменить с помощью
@Order
аннотации.Например:
import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.bind.annotation.ControllerAdvice; @ControllerAdvice @Order(Ordered.HIGHEST_PRECEDENCE) public class CustomExceptionHandler { //... }
@Order
Значение может быть любым целым числом.источник
Я также нашел в документации, что:
https://docs.spring.io/spring-framework/docs/4.3.4.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.html#getExceptionHandworklerMetprhod-rameframeing. web.method.HandlerMethod-java.lang.Exception-
Таким образом, это означает, что если вы хотите решить эту проблему, вам нужно будет добавить свой конкретный обработчик исключений в контроллер, генерирующий это исключение. ANd, чтобы определить один-единственный ControllerAdvice, обрабатывающий глобальный обработчик исключений по умолчанию.
Это упрощает процесс, и нам не нужна аннотация Order для решения проблемы.
источник
Похожая ситуация описана в отличном сообщении « Обработка исключений в Spring MVC » в блоге Spring в разделе, озаглавленном « Глобальная обработка исключений» . Их сценарий включает проверку аннотаций ResponseStatus, зарегистрированных в классе исключения, и повторное генерирование исключения, если оно есть, чтобы платформа могла их обработать. Возможно, вам удастся использовать эту общую тактику - попробуйте определить, есть ли более подходящий хендлер и повторите бросок.
В качестве альтернативы вы можете рассмотреть другие стратегии обработки исключений.
источник
Важный класс, который необходимо обработать:
**@Order(Ordered.HIGHEST_PRECEDENCE)** public class FunctionalResponseEntityExceptionHandler { private final Logger logger = LoggerFactory.getLogger(FunctionalResponseEntityExceptionHandler.class); @ExceptionHandler(EntityNotFoundException.class) public final ResponseEntity<Object> handleFunctionalExceptions(EntityNotFoundException ex, WebRequest request) { logger.error(ex.getMessage() + " " + ex); ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false),HttpStatus.NOT_FOUND.toString()); return new ResponseEntity<>(exceptionResponse, HttpStatus.NOT_FOUND); } }
Другие исключения с низким приоритетом
@ControllerAdvice public class GlobalResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { private final Logger logger = LoggerFactory.getLogger(GlobalResponseEntityExceptionHandler.class); @ExceptionHandler(Exception.class) public final ResponseEntity<Object> handleAllException(Exception ex, WebRequest request) { logger.error(ex.getMessage()+ " " + ex); ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.toString(), request.getDescription(false),HttpStatus.INTERNAL_SERVER_ERROR.toString()); } }
источник
вы также можете использовать числовое значение, как показано ниже
@Order(value = 100)
источник