✅ 스프링의 예외처리 방법
✔ 자바에서는 예외처리를 할 때 기본적으로 try-catch 문을 사용하는데, try-catch 문으로 여러 예외 처리를 작성하면 코드 자체가 굉장히 복잡해지고 지저분해진다.
✔ Spring에서는 예외처리 라는 공통 관심사를 메인 로직으로부터 분리하기 위해 다양한 예외 처리 방식을 제공한다.
✔ 여러 방식들 중, @ExceptionHandler 및 @ControllerAdivce를 사용한 예외처리 방법에 대해 정리해보자.
✅ @ExceptionHandler
- @ExceptionHandler는 컨트롤러의 메소드 또는 @ControllerAdvice, @RestControllerAdvice가 적용되어 있는 클래스의 메소드에 대해 발생하는 예외를 Catch하여 메소드 안에서 처리할 수 있도록 해주는 기능이다. (컨트롤러 외에 다른 곳에서는 적용 안됨)
@ExceptionHandler(value = NullPointerException.class)
처럼 Catch할 Exception을 지정해줄 수 있다.
- @ExceptionHandler는 특정 클래스(컨트롤러) 영역의 공통적인 예외 처리에 사용할 수 있다.
- 응닶(Return) 값을 제한적이지 않고 자유롭게 설정할 수 있다.
- 예제 코드
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
...
}
✅ @ControllerAdvice
- @ControllerAdvice는 모든 컨트롤러 전역에서 발생하는 예외를 처리할 수 있게 해주는 기능이다.
- 예를 들어, @ControllerAdvice를 적용한 클래스에서 메소드에 @ExceptionHandler(value = BidingException)를 추가하여 처리할 Exception을 지정해주면, 컨트롤러 전역에서 발생한 BindingException에 대해 해당 메소드 안에서 처리가 가능하다.
- @ControllerAdvice에는 @Component 어노테이션이 포함되어 있어서 @ControllerAdvice로 선언된 클래스는 스프링 빈으로 등록되므로 전역에서 발생하는 에러를 처리할 수 있게된다.
- 예제 코드
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoSuchElementFoundException.class)
protected ResponseEntity<?> handleIllegalArgumentException(NoSuchElementFoundException e) {
final ErrorResponse errorResponse = ErrorResponse.builder()
.code("Not Found")
.message(e.getMessage()).build();
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
}
}
ControllerAdvice의 사용 이점
- 하나의 클래스로 컨트롤러 전역에 대한 예외를 처리할 수 있다.
- 응답 값에 제한이 없으므로 직접 정의한 응답을 일관성있게 클라이언트에게 전달해줄 수 있다.
- try-catch 문을 사용하지 않아 코드의 가독성이 높아진다.
ControllerAdvice 사용 주의점
- 프로젝트 당 하나의 @ControllerAdvice를 사용하도록 권장된다.
- 여러 개를 사용하려면 basePackageClasses 및 basePackages와 같은 Selector를 사용해야 하며, OR연산을 통해 원하는 Selector를 찾는 로직이 추가되고 이는 런타임 시점에 실행되어 성능에 영향을 미치고 코드 복잡성이 높아질 수 있다.
✅ @ControllerAdvice 와 @RestControllerAdvice의 차이점
- @Controller와 @RestController 와 같이 @ResponseBody의 유무에 대한 차이다.
- @ControllerAdvice을 사용할 경우, 뷰 페이지로 리턴해주며 @RestControllerAdvice를 사용하면 응답 Body를 Json 형태로 내려주게 된다.
참고 Reference