📌 스프링의 기본 예외 처리 방법
- Spring이 만들어질 때부터 에러 처리를 위한 BasicErrorController가 구현되어 있었음
- 스프링 부트는 예외가 발생하면 기본적으로 /error로 에러 요청을 다시 전달하도록 WAS 설정을 해둠
- 따라서, 별도의 설정이 없는 경우 예외 발생 시 BasicErrorController로 에러 처리 요청이 전달됨
📌 스프링이 제공하는 다양한 예외 처리 방법
- Java에서는 예외 처리를 위해 try-catch를 사용해야 하지만, 모든 코드에 try-catch를 사용하는 것은 비효율적
- Spring은 에러 처리 전략을 추상화한 HandlerExceptionResolver 인터페이스를 만듬
- 대부분의 HandlerExceptionResolver는 발생한 Exception을 catch하고 HTTP 상태나 응답 메시지 등을 설정함
- 따라서, WAS 입장에서는 해당 요청을 정상적인 응답으로 인식함
- Spring에서는 아래와 같은 도구들로 ExceptionResolver를 동작시켜 에러를 처리할 수 있음
- ResponseStatus
- ResponseStatusException
- ExceptionHandler
- ControllerAdvice, RestControllerAdvice
1️⃣ @ResponseStatus
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class CommentNotFoundException extends RuntimeExceiption {
...
}
- 에러 HTTP 상태를 변경하도록 도와주는 어노테이션
- 적용 가능한 경우
- Exception 클래스 자체
- 메서드에
@ExceptionHandler
와 함께
- 클래스에
@RestControllerAdvice
와 함께
- BasicErrorController에 의해 응답이 이루어짐
- 👎 한계점
- 에러 응답 내용을 수정할 수 없음
- 예외 클래스와 강하게 결합되어 있기 때문에 같은 예외는 같은 상태와 에러 메시지를 반환함
- 별도의 응답 상태가 필요한 경우 예외 클래스를 추가해야 함
- WAS까지 예외가 전달되고 WAS의 에러 요청 전달이 진행됨
- 외부에서 정의한 Exception 클래스에는
@ResponseStatus
를 붙일 수 없음
2️⃣ ResponseStatusException
-
@ResponseStatus
의 프로그래밍적 대안으로 추가됨
-
HttpStatus와 함께 선택적으로 reason, cause 추가 가능
-
언체크 예외를 상속받기 때문에 명시적으로 에러를 처리하지 않아도 됨
-
👍 장점
- 기본적인 예외 처리를 빠르게 적용 가능
- HttpStatus를 직접 설정해 예외 클래스와의 결합도를 낮출 수 있음
- 불필요하게 많은 예외 클래스를 만들지 않아도 됨
- 프로그래밍 방식으로 예외를 직접 설정해 예외를 더 잘 제어할 수 있음
-
👎 한계점
- 프로그래밍 방식으로 예외를 직접 처리해 일관된 예외 처리가 어려움
- 예외 처리 코드가 중복될 수 있음
- Spring 내부의 예외 처리가 어려움
- 예외가 WAS까지 전달되고, WAS의 에러 요청 전달이 진행됨
3️⃣ ExceptionHandler
- 매우 유연하게 에러를 처리할 수 있는 방법을 제공
- 어노테이션을 추가할 수 있는 경우
- 컨트롤러의 메소드
@ControllerAdvice
나 RestControllerAdvice
가 있는 클래스의 메소드
- Exception 클래스들을 속성으로 받아 처리할 예외를 지정할 수 있음
- 예외 클래스를 지정하지 않는 경우 파라미터에 설정된 예외 클래스를 처리
@ResponseStatus
와 결합 가능
- 둘 다 Status를 지정하는 경우 Response Entity가 우선 순위를 가짐
@ResponseStatus
와 달리 응답을 자유롭게 다룰 수 있음
- code : 어떤 종류의 에러가 발생했는지에 대한 에러 코드 (가독성 좋은 값을 사용)
- message : 왜 에러가 발생했는지에 대한 설명
- errors : 어떤 값이 잘못되어
@Valid
에 의한 검증이 실패한 것인지를 위한 에러 목록
4️⃣ ControllerAdvice
, RestControllerAdvice
- 가장 좋은 방법
- 차이점 :
@ResponseBody
- 여러 컨트롤러에 대해 전역적으로 ExceptionalHandler를 적용해줌
- 👍 장점
- 하나의 클래스로 모든 컨트롤러에 대해 전역적으로 예외 처리가 가능함
- 직접 정의한 에러 응답을 일관성있게 클라이언트에게 내려줄 수 있음
- 별도의 try-catch문이 없어 코드의 가독성이 높아짐
- ❗️ 사용시 주의할 점
- 한 프로젝트당 하나의 ControllerAdvice만 관리
- 여러 ControllerAdvice가 필요하다면 basePackages나 annotations 등을 지정해야 함
- 직접 구현한 Exception 클래스들은 한 공간에서 관리