반응형
@ControllerAdvice와 @RestControllerAdvice에 대해 자세히 알아보자
📌 서론
프로그래밍에서 예외 처리는 매우 중요한 부분이며, Spring Boot에서는 @ControllerAdvice와 @RestControllerAdvice를 통해 이를 효율적으로 수행할 수 있다. 이 어노테이션들은 코드의 재사용성과 유지 보수성을 높여, 복잡한 비즈니스 로직에서도 예외 상황을 안정적으로 관리할 수 있게 해준다.
1. @ControllerAdvice이해
@ControllerAdvice란?
- @ControllerAdvice는 Spring 3.2에서 도입된 어노테이션으로, 모든 @Controller 클래스가 공유하는 공통 로직을 정의할 때 사용한다. 주로 예외 처리와 바인딩 설정, 모델 객체 등에 사용된다.
예제 코드
- 아래의 예제에서는 NotFoundException이 발생할 경우 "error"라는 이름의 뷰로 이동하고 메시지를 출력한다.
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler(NotFoundException.class)
public ModelAndView handleNotFoundException(NotFoundException ex) {
ModelAndView mav = new ModelAndView("error");
mav.addObject("message", ex.getMessage());
return mav;
}
}
2. @RestControllerAdvice 이해
@RestControllerAdvice란?
- @RestControllerAdvice는 @ControllerAdvice와 거의 동일하지만, 한 가지 큰 차이점은 이 어노테이션을 사용하면 @ResponseBody가 암시적으로 추가된다는 것이다. 따라서 JSON 형태로 바로 응답을 보낼 수 있다.
예제 코드
@RestControllerAdvice
public class GlobalRestControllerAdvice {
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<?> handleNotFoundException(NotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
}
}
주요 용어 설명
- ModelAndView: Spring MVC에서 모델과 뷰를 함께 전달할 수 있는 객체이다.
- ResponseEntity: HTTP 상태 코드와, 본문, 헤더 등을 포함한 응답을 표현한다.
- HttpStatus: HTTP 상태 코드(enum)을 나타낸다.
3. 작동 원리와 두 어노테이션의 비교
작동 원리
- Spring의 @ControllerAdvice와 @RestControllerAdvice는 AOP(Aspect-Oriented Programming)의 원리를 기반으로 동작한다. 즉, 이러한 어노테이션은 공통 관심사(cross-cutting concerns)인 예외 처리 로직을 분리하여 관리한다. 이를 통해 코드의 중복을 줄이고 유지보수성을 향상시킨다. 또한, 스프링 부트는 내부적으로 클래스패스를 스캔하여 이러한 어노테이션을 가진 클래스를 자동으로 등록하고 적용한다.
두 어노테이션은 매우 유사한 기능을 수행하지만 몇 가지 차이점이 있다.
응답 형식
- @ControllerAdvice: ModelAndView 객체를 반환하여 HTML 뷰를 렌더링할 수 있다.
- @RestControllerAdvice: ResponseEntity나 POJO 객체를 반환하여 JSON 형태로 응답할 수 있다.
사용처
- @ControllerAdvice: 주로 전통적인 Spring MVC와 함께 사용된다.
- @RestControllerAdvice: RESTful 웹 서비스에서 주로 사용된다.
암시적 어노테이션
- @ControllerAdvice: @ResponseBody를 명시적으로 추가해야 JSON을 반환할 수 있다.
- @RestControllerAdvice: 암시적으로 @ResponseBody가 추가되어 있어 별도로 추가할 필요가 없다.
어떤 것을 선택할까?
- 전통적인 웹 애플리케이션을 구축한다면 @ControllerAdvice가, RESTful API를 만든다면 @RestControllerAdvice가 더 적합하다. 또한 응답 형식, 사용처, 암시적 어노테이션 등을 고려하여 선택해야 한다.
4. 일반적으로는 이렇게 사용한다.
@ControllerAdvice 예제
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception ex) {
ModelAndView mav = new ModelAndView("error");
mav.addObject("message", ex.getMessage());
return mav;
}
}
@RestControllerAdvice 예제
@RestControllerAdvice
public class GlobalRestControllerAdvice {
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleException(Exception ex) {
Map<String, Object> errorDetails = new HashMap<>();
errorDetails.put("message", ex.getMessage());
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
5. 전략과 최적의 사례
특정 패키지나 클래스에 적용하기
- @ControllerAdvice나 @RestControllerAdvice를 사용할 때 basePackages 속성을 사용하여 특정 패키지나 클래스에만 적용할 수 있다.
@ControllerAdvice(basePackages = "com.example.controller")
public class GlobalControllerExceptionHandler {
// ...
}
우선순위 설정
- @Order 어노테이션을 사용하여 여러 개의 @ControllerAdvice나 @RestControllerAdvice 클래스 중 어떤 것이 먼저 실행될지 설정할 수 있다.
@Order(1)
@ControllerAdvice
public class GlobalControllerExceptionHandler {
// ...
}
예외 분류 및 커스터마이징
- 여러 종류의 예외를 처리하기 위해 @ExceptionHandler에 예외 타입을 배열로 지정할 수 있다.
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler({NotFoundException.class, AnotherException.class})
public ModelAndView handleMultipleExceptions(Exception ex) {
ModelAndView mav = new ModelAndView("error");
mav.addObject("message", ex.getMessage());
return mav;
}
}
비즈니스 로직과의 결합도 낮추기
- 비즈니스 로직 내부에서 발생하는 예외는 서비스 레이어에서 캡슐화하고, 이를 Controller에서는 @ControllerAdvice나 @RestControllerAdvice를 사용하여 공통적으로 처리하는 것이 유지보수성을 높인다.
다른 어노테이션과의 협업
- @ControllerAdvice나 @RestControllerAdvice는 @ExceptionHandler 외에도 @ModelAttribute, @InitBinder와 같이 사용할 수 있다.
@ControllerAdvice
public class GlobalControllerExceptionHandler {
@InitBinder
public void initBinder(WebDataBinder binder) {
// InitBinder 로직
}
@ModelAttribute
public void addAttributes(Model model) {
model.addAttribute("attribute", "value");
}
}
에러 로깅과 모니터링 전략
- 예외가 발생했을 때 이를 로깅하고 모니터링하는 전략도 중요하다. 예외 정보를 로그로 남기고 이를 모니터링 할 수 있는 툴을 사용하는 것이 유용하다.
controllerAdvice와 aop를 함께 사용하여 에러 로깅을 하는 방법이 궁금한다면?👇🏻👇🏻
반응형
'Spring 기초 > Spring 기초 지식' 카테고리의 다른 글
[Spring] 스프링과 자바의 동시성과 병렬 처리 (1) | 2023.10.31 |
---|---|
Spring: @ControllerAdvice와 AOP를 함께 사용하여 에러 로깅하기 (0) | 2023.10.24 |
[스프링, 스프링 부트] Spring - ajax로 호출하는 controller 메서드 구현방법 (2) | 2023.08.22 |
Spring: Maven과 Gradle의 차이 (0) | 2023.08.17 |
SpringBoot: 인터셉터(interceptor)의 동작원리 (0) | 2023.08.13 |