컨트롤러와 예외 처리 로직을 분리하여 코드 중복을 줄이고, 유지보수성 확보 및 관심사 분리 달성
@RestControllerAdvice를 통해 전역 예외 처리 클래스 선언
@RestControllerAdvice
public class GlobalExceptionHandler{
// 예외 핸들러 메서드 구현
}
이하 메서드 레벨에 @ExceptionHandler를 붙여 예외 타입별 핸들러 선언
파라미터로 처리할 예외 타입을 지정하고, 메서드 파라미터에 동일하게 넣어 줌
주의: 동일한 타입의 예외를 처리하는 핸들러가 둘 이상 있으면, 스프링 어플리케이션 실행 시점에 예외가 발생함
@RestControllerAdvice
public class GlobalExceptionHandler{
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponseDto> handleException(Exception e){
// 세부 오류 응답 로직 구현
}
}
다음과 같이 여러 타입의 예외를 중괄호로 묶어 처리하도록 하는 것도 가능
@ExceptionHandler({MethodArgumentNotValidException.class, JsonMappingException.class})
@ControllerAdvice 및 @RestControllerAdvice 가 붙은 클래스들은 스프링 시작 시점에 빈으로 등록됨
클라이언트 요청 수신 시 DispatcherServlet이 컨트롤러를 호출하는 과정에서 발생한 처리되지 않은 예외들을 캐치하고, 스프링 컨테이너에서 해당 예외 타입과 일치하는 핸들러를 찾은 다음 적절한 반환값을 돌려받아 최종 응답을 구성 (이때 @ControllerAdvice는 View 자체를, @RestControllerAdvice는 JSON을 반환)
결국 DispatcherServlet이 모든 요청을 중앙 집중 방식으로 처리하는 Spring의 구조 덕분에 예외 처리도 일원화가 가능함