IT박스

여러 @ControllerAdvice @ExceptionHandlers의 우선 순위 설정

itboxs 2020. 11. 16. 07:59
반응형

여러 @ControllerAdvice @ExceptionHandlers의 우선 순위 설정


으로 주석이 달린 다중 클래스가 @ControllerAdvice있으며 각각 @ExceptionHandler메서드가 있습니다.

Exception특정 핸들러가 더 이상 발견되지 않으면이를 사용해야한다는 의도로 처리합니다 .

슬프게도 Spring MVC Exception는 더 구체적인 경우 ( IOException:)보다는 항상 가장 일반적인 경우 ( )를 사용하는 것으로 보입니다 .

이것이 Spring MVC가 동작 할 것으로 기대하는 방식입니까? ExceptionMapper처리하는 선언 된 유형이 throw 된 예외에서 얼마나 멀리 떨어져 있는지 확인하고 항상 가장 가까운 조상을 사용하는 (동등한 구성 요소)을 평가하는 Jersey에서 패턴을 에뮬레이션하려고합니다 .


이것이 Spring MVC가 동작 할 것으로 기대하는 방식입니까?

Spring 4.3.7부터 Spring MVC가 작동하는 방식은 다음과 같습니다. HandlerExceptionResolver인스턴스를 사용 하여 핸들러 메서드에서 발생한 예외를 처리합니다.

기본적으로 웹 MVC 구성은 하나의 등록 HandlerExceptionResolverbean을하는 HandlerExceptionResolverComposite, 어떤

다른 HandlerExceptionResolvers.

다른 리졸버는

  1. ExceptionHandlerExceptionResolver
  2. ResponseStatusExceptionResolver
  3. DefaultHandlerExceptionResolver

그 순서대로 등록되었습니다. 이 질문의 목적을 위해 우리는 ExceptionHandlerExceptionResolver.

메서드를 AbstractHandlerMethodExceptionResolver통해 예외를 해결 하는 입니다 @ExceptionHandler.

컨텍스트 초기화에서 Spring은 감지 ControllerAdviceBean하는 각 @ControllerAdvice주석이 달린 클래스 에 대해 생성합니다 . ExceptionHandlerExceptionResolver상황에서 이러한를 검색하고이를 사용하여 정렬합니다 AnnotationAwareOrderComparator있는

은 (는) 정적으로 정의 된 주석 값 (있는 경우)을 재정의하는 Ordered 인스턴스에서 제공하는 주문 값과 함께 주석 뿐 아니라 OrderComparatorSpring의 Ordered인터페이스 를 지원 하는의 확장입니다 .@Order@Priority

그런 다음 ExceptionHandlerMethodResolverControllerAdviceBean인스턴스 에 대해 를 등록 합니다 (사용 가능한 @ExceptionHandler메서드를 처리하려는 예외 유형에 매핑 ). 마지막으로 동일한 순서로 a에 추가됩니다 LinkedHashMap(반복 순서 유지).

예외가 발생 ExceptionHandlerExceptionResolver하면는 이러한 항목을 반복 ExceptionHandlerMethodResolver하고 예외를 처리 할 수있는 첫 번째 항목을 사용합니다.

여기에 포인트 그래서입니다 : 당신이있는 경우 @ControllerAdvice@ExceptionHandler대한 Exception그 다른 이전에 등록됩니다 @ControllerAdvice와 클래스 @ExceptionHandler보다 구체적인 예외, 등에 IOException, 첫 번째가 호출되는 것이다. 앞서 언급 한 바와 같이, 당신은 당신의 필요에 의해 그 등록 순서를 제어 할 수 @ControllerAdvice주석 클래스가 구현 Ordered또는 그것을 주석 @Order또는 @Priority그것에게 적절한 값을 제공합니다.


Sotirios Delimanolis는 그의 답변에 매우 도움이되었습니다. 추가 조사에서 우리는 어쨌든 봄 3.2.4에서 @ControllerAdvice 주석을 찾는 코드가 @Order 주석의 존재를 확인하고 ControllerAdviceBeans 목록을 정렬한다는 것을 발견했습니다.

@Order 주석이없는 모든 컨트롤러의 결과 기본 순서는 Ordered # LOWEST_PRECEDENCE입니다. 즉, 가장 낮은 우선 순위가 필요한 컨트롤러가 하나 있으면 모든 컨트롤러의 순서가 더 높아야합니다.

다음은 UserProfileException 또는 RuntimeException이 발생할 때 적절한 응답을 제공 할 수있는 ControllerAdvice 및 Order 주석이있는 두 개의 예외 핸들러 클래스를 갖는 방법을 보여주는 예입니다.

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() {
        ....
    }
}
  • ControllerAdviceBean # initOrderFromBeanType ()을 참조하십시오.
  • ControllerAdviceBean # findAnnotatedBeans ()를 참조하십시오.
  • ExceptionHandlerExceptionResolver # initExceptionHandlerAdviceCache ()를 참조하십시오.

즐겨!


예외 처리기의 순서는 @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#getExceptionHandlerMethod-org.springframework.web.method.HandlerMethod-java.lang.Exception-

ExceptionHandlerMethod

protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception)

Find an @ExceptionHandler method for the given exception. The default implementation searches methods in the class hierarchy of the controller first and if not found, it continues searching for additional @ExceptionHandler methods assuming some @ControllerAdvice Spring-managed beans were detected. Parameters: handlerMethod - the method where the exception was raised (may be null) exception - the raised exception Returns: a method to handle the exception, or null

So this means that if you want to solve this issue, you will need to add your specific exception handler within the controller throwing those exception. ANd to define one and only ControllerAdvice handling the Global default exception handler.

This simplies the process and we don't need the Order annotation to handle the problem.


There's a similar situation convered in the excellent "Exception Handling in Spring MVC" post on the Spring blog, in the section entitled Global Exception Handling. Their scenario involves checking for ResponseStatus annotations registered on the exception class, and if present, rethrowing the exception to let the framework handle them. You might be able to use this general tactic - try to determine if there is a might be a more appropriate handler out there and rethrowing.

Alternatively, there's some other exception handling strategies covered that you might look at instead.

참고URL : https://stackoverflow.com/questions/19498378/setting-precedence-of-multiple-controlleradvice-exceptionhandlers

반응형