@ExceptionHandler 동작원리

데일리·2024년 11월 6일

TIL

목록 보기
3/16
post-thumbnail

보통 우리가 MVC 구조의 코드를 구현하다보면 필연적으로 나오는게 Exception 처리 즉 예외처리를 하고는 한다. 이를 구현해주는게 스프링에서는 ExceptionHandler가 있다. 과연 스프링 ExceptionHandler는 어떻게 동작하는지 알아보자

@ExeceptionHandler??

@ControllerAdvice 또는 특정 컨트롤러 클래스 내에 특정 예외가 발생했을 때 이를 처리하기 위한 메서드를 정의할 수 있도록 지원하는 어노테이션이고 이를 통해 예외 발생 시 프로그램의 흐름을 중단하지 않고, 오류를 보다 유연하게 처리하거나 사용자에게 알맞은 메시지를 반환하게 한다.

즉 예외 처리를 WAS로 바로 넘기는게 아니라 이를 직접처리하여 로깅 혹은 유저 친화적인 에러 메시지로 변경할 수 있다는 것이 중요하다.

예시를 보면 아래와 같다.

@RestController
public class MyController {

    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<String> handleNullPointerException(NullPointerException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Null 값이 발생했습니다: " + e.getMessage());
    }

위에서는 nullPointerException이 발생했을 시 ExeceptionHandler의 사용자 정의 메서드를 정의하여 특정 메시지를 반환해주는 로직을 추가했다.

@ExeceptionHandler의 장점

위에서 봤다시피 @ExeceptionHandler의 큰 장점은 에러 발생 시 was에 넘기기 전에 사용자 정의 메서드를 거친다는 것이다. 이 뿐만이 아니라 몇가지 장점이 더 있는데 아래와 같다.

  • 예외 처리를 중앙에서 관리할 수 있어 코드 가독성 향상 및 유지보수 쉬워짐
  • 예외 상황에 따라 사용자 맞춤 응답을 정의
  • 응답 상태 코드, 메시지 등을 일관되게 관리

@ExeceptionHandler 동작 원리

  1. 예외 발생 시 컨트롤러 호출 중단
  • HTTP 요청을 처리하는 컨트롤러에서 예외가 발생하면 Spring은 즉시 해당 요청의 처리를 중단하고, 예외 핸들링 로직으로 흐름을 전환
  1. @ExceptionHandler 메서드 탐색
  • 예외가 발생한 컨트롤러 클래스 내에서 @ExceptionHandler가 정의된 메서드를 찾아, 해당 예외에 대한 처리 메서드가 있는지 탐색한다.(1단계 예외 발생한 컨트롤러 내부 -> 2단계 @ControllerAdvice로 정의된 전역 예외 핸들러)
  1. 예외 타입 일치 여부 확인
  • 탐색된 @ExceptionHandler 메서드에서 매개변수로 선언된 예외 타입과 발생한 예외 타입을 비교하여 타입이 일치하거나 상속 관계가 있는지 확인
  • 예외 타입이 일치하는 @ExceptionHandler 메서드가 발견되면 해당 메서드를 실행하고, 일치하는 메서드가 없으면 기본 오류 페이지 또는 사용자 정의 오류 페이지를 반환한다.
  1. ExceptionHandlerMethodResolver
  • Spring은 내부적으로 ExceptionHandlerMethodResolver라는 클래스를 사용하여 @ExceptionHandler가 붙은 메서드들을 관리하고, 요청에 대해 적합한 예외 처리 메서드를 선택한다.
  1. 예외 처리 메서드의 응답 반환
  • 선택된 @ExceptionHandler 메서드가 예외를 처리하고, 응답을 생성하여 클라이언트에게 반환하고 이때 응답은 ResponseEntity, JSON 응답, 텍스트 응답 등으로 지정할 수 있다.

아래 예시를 보면 이해가 빠를 것이다.


@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<String> handleNullPointerException(NullPointerException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                             .body("Null 값이 발생했습니다.");
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGenericException(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                             .body("서버 오류가 발생했습니다.");
    }
}

예시의 동작 흐름을 살펴보면

  • 우선 예외가 발생하면 ExceptionHandlerMethodResolver를 통해 @ExceptionHandler 메서드를 찾는다.
  • 일치하는 메서드를 발견하면 이를 호출하여 예외를 처리하고, HTTP 상태 코드와 응답 본문을 설정하여 반환
  • 일치하는 @ExceptionHandler 메서드가 없을 경우, 기본 예외 처리 로직으로 돌아간다.
  • 이 과정을 통해 @ExceptionHandler는 요청 흐름에 개입하여 예외를 효율적으로 처리하고, 사용자에게 적절한 메시지를 전달.
profile
하루에 한편 씩 읽기 좋은 테크 로그

0개의 댓글