설정 우선 순위는


41

난에 @ExceptionHandler 방법 @ControllerAdvice 각 주석 곱셈기 클래스가 있습니다.

하나는 더 이상 특정 핸들러가 발견되지 않는 경우,이 사용하는 것을 목적으로 Exception을 처리합니다.

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

스프링 MVC가 어떻게 동작 할 것으로 예상 되는가? Jersey에서 각 ExceptionMapper (동등한 구성 요소)을 평가하여 처리되는 선언 된 유형이 발생한 예외로부터 얼마나 멀리 있는지를 판별하고 항상 가장 가까운 조상을 사용하는 패턴을 에뮬레이트하려고합니다.

51

스프링 MVC가 어떻게 동작 할 것으로 예상 되는가?

Spring 4.3.7부터는 Spring MVC의 동작 방식이 다음과 같습니다. HandlerExceptionResolver 인스턴스를 사용하여 핸들러 메소드에서 발생하는 예외를 처리합니다. 기본적으로

는 웹 MVC 구성은 하나의 HandlerExceptionResolver 빈하는 HandlerExceptionResolverComposite, 다른 HandlerExceptionResolvers 목록에

대표를 등록합니다.

리졸버는 그 다른

  • ResponseStatusExceptionResolverDefaultHandlerExceptionResolver
    1. ExceptionHandlerExceptionResolver
    2. 이 순서대로 등록된다. 이 질문의 목적을 위해 우리는 ExceptionHandlerExceptionResolver 만 신경 쓰고 있습니다.

      AbstractHandlerMethodExceptionResolver@ExceptionHandler 방법을 통해 예외를 를 해결합니다.

      컨텍스트 초기화시 Spring은 감지 된 주석이있는 각 클래스에 대해 ControllerAdviceBean을 각 @ControllerAdvice에 생성합니다. ExceptionHandlerExceptionResolver는 상황에서 이러한를 검색하고

      이가 제공하는 주문 값뿐만 아니라 @Order@Priority 주석 등 봄의 Ordered 인터페이스를 지원 OrderComparator의 확장이되는 AnnotationAwareOrderComparator를 사용하여 사용하여 정렬합니다 정의 된 주석 값 (있는 경우)을 정적으로 재정의하는 정렬 된 인스턴스입니다.

      그 다음이 ControllerAdviceBean 인스턴스 (그들이 처리하기 위해 의미있는 예외 유형에 매핑을 사용할 수 @ExceptionHandler 방법)의 각각에 대한 ExceptionHandlerMethodResolver을 등록 할 수 있습니다. 이것들은 마침내 같은 순서로 LinkedHashMap (반복 순서를 유지함)에 추가됩니다.

      예외가 발생하면 ExceptionHandlerExceptionResolverExceptionHandlerMethodResolver을 반복하고 예외를 처리 할 수있는 첫 번째 예외를 사용합니다.

      그래서 여기에 요점은 : 당신이 IOException 같은보다 구체적인 예외에 대한 @ExceptionHandler와 다른 @ControllerAdvice 클래스 이전에 등록됩니다 Exception에 대한 @ExceptionHandler 가진 @ControllerAdvice이있는 경우, 첫 번째가 호출되는 것이다. 앞에서 언급했듯이 @ControllerAdvice 주석이 달린 클래스에 Ordered을 구현하거나 @Order 또는 @Priority으로 주석을 추가하고 적절한 값을 지정하여 등록 순서를 제어 할 수 있습니다.


    2

    우수 블로그 "Exception Handling in Spring MVC"의 게시물 (Global Exception Handling 섹션 참조)에서 비슷한 상황이 발생합니다. 이 시나리오에는 예외 클래스에 등록 된 ResponseStatus 주석이 있는지 확인하는 작업과 프레임 워크가 프레임 워크를 처리 할 수 ​​있도록 예외를 다시 게시하는 작업이 포함됩니다. 이 일반적인 전술을 사용할 수 있습니다. 거기에 더 적절한 처리기가 있을지와 재실행 중인지 확인하십시오.

    다른 방법으로는 예외 처리 전략이 있습니다.


    58

    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()

    즐기십시오!


    15

    예외 처리기의 순서는 @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의 값은 임의의 정수가 될 수있다.


    1

    나는 또한 문서에서 발견 :

    ExceptionHandlerMethod

    ServletInvocableHandlerMethod getExceptionHandlerMethod (HandlerMethod handlerMethod, 예외 예외)

    지정된 예외에 대한 @ExceptionHandler 방법을 찾으 보호. 기본 구현에서는 클래스의 메소드 을 먼저 검색하고 찾을 수없는 경우 @ControllerAdvice 스프링 관리 Bean이 감지 된으로 가정하여 추가 @ExceptionHandler 메소드를 계속 검색합니다 (이 경우 ). 매개 변수 : handlerMethod - 예외 예외 ( null의 경우도있다) 제기 된 방법 - 제기 예외 반환 값 : 예외를 처리하는 방법, 또는 null

    그래서 당신이 원하는 경우 해결하는 것을 의미한다 이 문제가 발생하면 해당 예외를 던지는 컨트롤러 내에 특정 예외 처리기를 추가해야합니다. 전역 기본 예외 처리기를 처리하는 하나의 ControllerAdvice 만 정의 할 수 있습니다.

    이렇게하면 프로세스가 단순 해지며 문제를 처리하기 위해 주문 주석이 필요하지 않습니다.