애플리케이션을 개발하다보면, Exception(예외)처리를 하게된다. 예외에 대한 처리로직이 없다면, 애플리케이션이 뻗어(?)버리는 대참사가 발생하기 때문에 예외처리 로직은 필수적이다. 예외처리 로직은 아마도, 애플리케이션의 가장 상위 계층에서 이뤄질 것이다. 일반적으로 웹 애플리케이션의 경우, Web Controller(혹은 각 계층의 최상위 클래스) 가 해당 역할을 할 것 이다. 그리고 에러를 다루는 계층은 내부의 여렇 계층에서 발생하는 모든 예외를 다둘것이며, 이는 해당 계층을 이해하기 어렵게 만든다. 조금 더 엄격하게 이야기를 한다면, 해당 계층의 코드를 감히 오염 시킨다고 이야기할 수 있을 것 같다.
에러처리는 필수적이다. 하지만 이런 중첩된 try-catch 를 활용하는 방법은 피하고 싶다. 그런데 어떻게..? 하는 사람들에게 @ControllerAdvice 를 추천하고 싶다.
@ControllerAdvice
@ControllerAdvice 는 org.springframework.web.bind.annotation 패키지에 위치해 있는 어노테이션으로, @ControllerAdvice로 어노테이션된 클래스의 메서드는 모든 컨트롤러에 전역적으로 적용되며, annotations, assignableTypes, basePackageClasses, basePackages와 같은 selector 를 사용하여 적용할 컨트롤러의 구체적인 하위 집합(범위)을 지정 할 수 있다.
예외 처리는, 첫 번째 @ControllerAdvice 에서 일치하는 예외 처리기 메서드가 있는 @ExceptionHandler가 선택된다.
좀더 자세한 설명을 공식문서를 통해 이야기해본다면, 다음과 같다.
@ControllerAdvice 주석을 단 클래스는 명시적으로 Spring Bean 으로 선언하거나 클래스 경로 검색을 통해 자동으로 감지 될 수 있다. 그리고 이러한 모든 Bean 은 Ordered 시맨틱 또는 @Order/@Priority 선언을 기반으로 정렬되며, Ordered 시맨틱이 @Order/@Priority 보다 우선된다. 그러나 PriorityOrdered를 구현하는 @ControllerAdvice 빈은 Ordered를 구현하는 @ControllerAdvice Bean 보다 우선순위가 부여되지 않는다는 점에 주의해야 한다.
또한 범위가 지정된 @ControllerAdvice 빈(예: 해당 빈이 요청 범위 또는 세션 범위 빈으로 구성된 경우)에 대해서는 Ordered가 적용되지 않는다.
더 자세한 이야기는 공식문서를 참고하는 것이 좋을 것 같다.
ControllerAdvice (Spring Framework 6.0.11 API)
Specialization of @Component for classes that declare @ExceptionHandler, @InitBinder, or @ModelAttribute methods to be shared across multiple @Controller classes. Classes annotated with @ControllerAdvice can be declared explicitly as Spring beans or auto-d
docs.spring.io
적용
나는 @ControllerAdvice 를 적용하여 Web 계층을 개발했고, 이를 사용함으로써, 파이썬 프로젝트 개발 때 불편했던 부분을 개선할 수 있었다. 코드를 좀더 명확하게 표현하고 해당 클래스를 쉽게 이해할 수 있게 되었다.
기본적으로 GlobalExceptionHandler 를 생성하였다. 해당 클래스를 상속하여, 각 도메인에 알맞은 에러 핸들링을 하도록 설정하고, 지정되지 않은 에러에 대해서도 처리 할 수 있도록 하였다.
ProductGlobalExceptionHandler 는 현재 Product 도메인에서 발생 시키는 에러를 처리한다. Product 도메인에서 다루는 에러는 ProductDomainException, ProductNotFoundException, ProductDTOException 이 존재한다.
그리고 basePackages 설정을 통해 범위를 지정한 하위 패키지에 속한 컨트롤러에만 적용되도록 하였다.(불필요한 전역범위에 적용되지 않도록 하였다.)
하지만 @ControllerAdvice를 사용하면서 문제점들도 존재했다. 그리고 그에 관한 이야기는 TIL, 과 적용한 프로젝트의 Issue로 다루었다.
TIL
태풍, GlobalMemberExceptionHandler error 이슈 해결, Order 개발
오늘은 태풍 때문인지 날씨가 많이 선선하니 좋았으나, 비가 많이오고, 날씨가 많이 흐렸다. 이 때문인지 금방 해결할 것같던 GlobalMemberExceptionHandler error 이슈는 생각보다 해결에 애를 먹었다. 정
sykeem.tistory.com
Issue/PR
GlobalMemberExceptionHandler 의 오류를 개선한다. · Issue #9 · KEEMSY/shoes-ordering-system
설명 기준 버전/ 커밋: c62fb39 // MemberGlobalExceptionHandler 의 일부분 @ResponseBody @ExceptionHandler(value = {MemberDomainException.class}) @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorDTO handlerExc...
github.com
Bug/fix GlobalMemberExceptionHandler error(GlobalMemberExceptionHandler 의 작동 오류) by KEEMSY · Pull Request #10 · KEEM
관련 이슈 GlobalMemberExceptionHandler 의 오류를 개선한다. #9 변경 사항 MemberController 테스트 를 추가하고, GlobalMemberExceptionHandler 의 오류 확인 및 수정 하였습니다. GlobalMemberExceptionHandler 의 오류를 수
github.com
정리
예외처리는 필수적이지만, 복잡한 예외처리는 해당 처리 로직을 이해하기 힘들게 만든다. 스프링 애플리케이션의 웹 계층(Controller)에서는, @ControllerAdvice 를 사용하여 처리 로직과 에러핸들링을 분리하여, 처리로직을 보다 명확하게 만들 수 있다.
@ControllerAdvice로 어노테이션된 클래스의 메서드는 모든 컨트롤러에 전역적으로 적용되며, 다양한 selector 를 사용하여 적용할 컨트롤러의 구체적인 하위 집합(범위)을 지정 할 수 있다. 예외 처리의 경우, 첫 번째 @ControllerAdvice 에서 일치하는 예외 처리기 메서드가 있는 @ExceptionHandler가 선택된다.
'개인공부' 카테고리의 다른 글
[ 코드 설계 ] 의존성 역전 원칙 과 의존성 주입 프레임 워크 (0) | 2023.10.06 |
---|---|
[ 코드 설계 ] 개방 폐쇄 원칙 OCP (0) | 2023.09.28 |
[ 코드 설계 ] 단일 책임 원칙 SRP (0) | 2023.09.26 |
[ JPA ] save() 전에, UPDATE 전에 왜 SELECT 가 발생할까? + INSERT 전에 SELECT 가 발생하는 이유는 무엇일까? (0) | 2023.09.22 |
[ Java ] Optional (0) | 2023.09.18 |