Exception 이란?
기본적으로 예외처리를 하려면 Exception의 개념부터 알아야 합니다.
Exception이란, 위의 사진과 같이 Object와 Throwable을 상속하는 서브 클래스입니다.
Exception은 예외적인 상황을 처리하기 위해 자바에서 제공하는 클래스 입니다.
Exception에서도 CheckedException과 UncheckedException 두가지로 나뉘게 됩니다.
CheckedException은 체크된 예외라고 합니다. 체크된 예외는 프로그래머가 컴파일 시점에 반드시 처리해줘야하는 예외입니다.
UncheckedException은 체크되지 않은 예외입니다.
체크되지 않은 예외는 프로그래머가 알지못하는 상황에 일어납니다. 즉, 어플리케이션이 실행 도중 발생하는 예외라고 볼 수 있습니다.
대표적으로는 RuntimeException이 존재합니다. (Runtime - 실행중, Exception - 예외)
두가지의 가장 큰 차이점은, 컴파일 전,후에 알 수 있는가 입니다.
try-catch와 throw
두가지 모두 CheckedException을 처리하는 방식입니다.
CheckedException을 처리하는 방법은 크게 두가지가 존재합니다.
try-catch는 영어 원문으로 해석하면 실행하고 잡다 입니다.
자바 컴파일러는 CheckedException이 발생할 가능성이 있는 코드를 작성할 때, 반드시 예외를 처리하거나 호출자에게 전달하도록 강제합니다.
이를 통해 프로그램의 안정성을 확보하고, 예외에 따른 행동을 정의할 수 있도록 만들어 줍니다.
두번째로 throw는 원문 해석시, 던지다 입니다.
throw는 자바에서 예외를 발생시키거나 호출자에게 전달할 때 사용됩니다.
throw는 특정 조건에서 직접 예외를 발생시킬 때 사용합니다.
throws는 메서드가 예외를 던질 가능성이 있음을 호출자에게 알리고, 호출자에게 예외 처리 책임을 위임할 때 사용합니다.
Spring에서 예외처리를 하는법
스프링에서는 어노테이션을 통해 예외를 효울적으로 처리하도록 도와줍니다.
@ControllerAdvice와 @RestControllerAdvice 입니다.
두가지 어노테이션은 모두 예외처리를 할 수 있도록 도와줍니다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
...
}
위의 코드를 보면 RestControllerAdvice가 ControllerAdvice 어노테이션을 상속받습니다.
@RestControllerAdvice는 @ControllerAdvice와 다르게, @ResponseBody가 붙어 있어 응답을 Json으로 내려줍니다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
...
}
ControllerAdvice는 Component 어노테이션이 존재합니다.
그렇기 때문에 ControllerAdvice가 적용된 클래스는 자동으로 스프링 빈에 등록됩니다.
스프링 빈에 등록되면 DI Container에 등록되게 되며 싱글톤으로 관리되고, 전역적으로 사용할 수 있도록 구현체가 만들어집니다.
이를 통해 전역적으로 에러 핸들링을 하는 객체를 만들어, 에러 처리를 하나의 객체에 위임시킬 수 있습니다.
@ExceptionHandler
그리고 @ControllerAdvice와 함께 많이 사용되는 어노테이션은 @ExceptionHandler가 있습니다.
@ExceptionHandler같은 경우는 @Controller, @RestController가 적용된 스프링 빈 내부에서 발생하는 예외를 잡아서,
하나의 메서드에서 처리해주는 기능을 담당합니다.
이렇게 ControllerAdvice를 통한 ExceptionHandler는 다음과 같은 순서로 동작합니다.
- @ControllerAdvice는 @Component 어노테이션이 적용되어 있기 때문에, 스프링 빈에 등록되고 전역적으로 사용됩니다.
- @ControllerAdvice가 적용된 클래스 내부 메서드에 @ExceptionHandler를 적용시켜 예외처리를 합니다.
- @ExceptionHandler는 매개변수로 Exception 클래스를 받습니다.
- 예를 들어, @ExceptionHandler(RuntimeException.class)는 어플리케이션의 모든 RuntimeException을 처리하는 메서드가 됩니다.
@ControllerAdvice와 @ExceptionHandler 사용 예시
먼저 어플리케이션의 Exception을 처리하기위해 객체를 하나 만들고, @ControllerAdvice를 등록시킵니다.
@RestControllerAdvice
public class GlobalExceptionHandler {
}
그리고 우리가 처리하고 싶은 Exception을 @ExceptionHandler의 매개변수로 추가하고 그에 따른 로직을 메서드로 구현합니다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public String handleRuntimeException(RuntimeException e) {
return e.getMessage();
}
}
위의 메서드는 RuntimeException이 들어오면 Exception 객체의 message를 반환하도록 하는 메서드입니다.
이렇게 구현하게 되면, 어플리케이션의 모든 RuntimeException은 handleRuntimeException 메서드를 통해 처리되게 됩니다.
실제로 어플리케이션에서 임의로 RuntimeException을 던져보겠습니다.
@Controller
public class ExceptionTestController {
@GetMapping("/test")
public void exceptionTestApi() {
throw new RuntimeException("Exception Handler Test");
}
}
Controller에서 /test url로 요청을 보내면, RuntimeException을 던지도록 만든 메서드입니다.
그리고 url로 웹 요청을 보낸 결과를 확인합니다.
위의 사진처럼 성공적으로 예외처리를 한 모습입니다.
결론
스프링에서는 ControllerAdvice를 통해 예외를 전역적으로 관리하는 스프링 빈을 등록할 수 있다.
ExceptionHandler 어노테이션을 적용시키고 매개변수로 Exception 클래스를 넣어주면, Exception 클래스에 맞는 예외가 들어오면 하위 메서드를 통해 처리하도록 도와준다.
'BackEnd' 카테고리의 다른 글
[Spring] Filter에서 Exception을 관리하는 법 (0) | 2024.12.19 |
---|---|
[DB] 효율적인 설계를 위해 어떤 SQL을 사용해야 할까? RDBMS vs NoSQL과 DB에서의 수직 확장(scale-up)과 수평 확장(scale-out) (0) | 2024.06.20 |
[Spring] 스프링이 사랑한 디자인 패턴 - 1 (0) | 2024.05.29 |
[Spring] BeanFactory와 ApplicationContext 이해하기 (0) | 2024.04.03 |
[Spring] 스프링 컨테이너와 빈 (0) | 2024.04.02 |