[ 티스토리 ]

새벽의 공부 이야기

home

tags

태그

guestbook

방명록

manage

관리

profile

프로필

2. HandlerExceptionResolver에 대하여

2024. 3. 18.

Spring/Spring Boot

스프링 부트의 다양한 예외 처리 방식을 실현하는 HandlerExceptionResolver에 대한 글이다.


1. 예외 처리

Exception이 발생하면, @ControllerAdvice, @ExceptionHandler 등으로 빈에 등록된 여러 클래스에 의해 처리된다.

 

이러한 클래스들을 이용해서 DispatcherServlet까지 전해진 예외가 처리 가능한지 확인하고,

가능한 클래스에게 예외 처리를 위임하는, HandlerExceptionResolver에 대해서 이야기를 하려 한다.

 

2. Status Code와 Exception

일부 Exception들은, API를 사용하는 사용자(클라이언트)에게 Status Code를 500이 아닌 다른 코드를 표시해줘야할 이유가 있다.

예를 들어, Controller에서 유효성 검증 실패로 Exception이 발생한 경우 사용자에게 400 Bad Request를 표시해줘야 한다.

 

이러한 처리들을 하는 클래스를 찾고, 그것들을 실행하는 역할을 하는 객체가 바로 HandlerExceptionResolver의 구현체들이다.

- resolveException 메소드 의역
HandlerExecutionChain을 실행하는 도중에 발생한 예외의 처리를 시도하며, 적절한 에러 페이지를 담은 ModelAndView 객체를 반환합니다.
예외가 성공적으로 처리되었지만 화면이 표시되면 안된다는 것을 말하기 위해 ModelAndView가 비어있을 수도 있습니다. 이를 위해 상태 코드를 설정하는 등의 방법을 사용할 수 있습니다.

 

스프링부트의 기본 예외 처리기인, DefaultHandlerExceptionResolver를 보면 자주 발생하는 일부 스프링 예외들에 대해 StatusCode를 자동으로 설정해주는 코드가 존재한다.

위는 그러한 DefaultHandlerExceptionResolver의 일부 코드이다.

 

만약 doResolveException( = resolveException) 메소드의 파라미터로 HttpRequestMethodNotSupportedException 타입의 Exception이 입력되었다면, 그에 맞는 405 상태 코드를 반환한다.

이러한 것과 같은 기능을 하는 클래스가 HandlerExceptionResolver이다.

 

3. HandlerExceptionResolver의 종류와 DispatcherServlet에서의 처리 순서

DispatcherServelt에서 사용하는 HandlerExceptionResolver는  세 가지의 구현체가 존재한다.

1. ExceptionHandlerExceptionResolver

2. ResponseStatusExceptionResolver

3. DefaultHandlerExceptionResolver

ExceptionHandlerExceptionResolver

예외들 중, @ControllerAdvice, @ExceptionHandler 등으로 처리할 Exception인지 확인하고, 처리를 위임하는 클래스

 

ResponseStatusExceptionResolver

예외들 중, @ResponseStatus를 통해 Status Code가 지정되어 있는 Exception인지 확인한 후, 그 내용에 맞게 Response를 수정하는 클래스

실제로 @ResponseStatus의 Docs를 보면 아래와 같이 ResponseStatusExceptionResolver가 @see로 연결되어 있다.

 

DefaultHandlerExceptionResolver

앞의 두 클래스로도 처리되지 않은 Exception일 경우, 최종적으로 스프링의 Exception 중 하나인지 확인하고 그에 맞는 처리를 하는 클래스

 

이 클래스들은 DispatcherServelt에서 사용되며,

doService() -> doDispatch() -> processDispatchResult() -> processHandlerException()

위 메소드 체인에 걸쳐 아래 필드까지 도달해 Exception을 처리한다.

DispatcherServlet의 초기화 메소드, initHandlerExceptionResolvers 실행 중 Debugging 모드를 이용해 추출한 ExceptionResolver들
DispatcherServlet의 processHandlerException 메소드의 일부

위 두 개 사진을 보면 알 수 있듯, 위에서 나열한 세 개의 클래스는 DefaultErrorAttributes를 실행한 후 HandlerExceptionResolverComposite에 감싸져 실행된다.

 

DefaultErrorAttributes

로직과 크게 관계있지 않은 클래스다. 존재 여부만 알고 넘어가겠다.

 

HandlerExceptionResolverComposite

위에서 나열한 3개의 HandlerExceptionResolver 구현체를 담고 있는 일종의 프록시 클래스이다.

 

세 개 Resolver들을 FilterChain처럼 순회한다.

위에서 나열한 순서를 우선순위로, Exception을 처리할 수 있을 경우 그 결과를 반환한다.


글을 읽는 이들에게 도움이 되었길 바라며, 이상으로 글을 마치도록 하겠다.