@ExceptionHandler
예외 처리기가 어떻게 동작하는지에 대해서 궁금했어서
업무중에 돌려보게 되었다. (예제코드는 다시 작성할 예정)
일단 동작과정은 DB에서 해당 id를 찾아 검색했을 때 없을 경우 예외를 던져주게 하는
예시
간단하게 보면
public class UserService {
private final UserRepository userRepository;
public User findById(final int id) {
return userRepository.findById(id)
.orElseThrow(() -> new NotFoundException("해당 유저를 찾을 수 없습니다"));
}
}
라고 로직을 구성했을 때 이 로직의 예외에 대한 핸들러 동작을 파보게 되었다.
일단 get 메소드로 조회 로직을 수행하고
그 요청을 RequestMappingHandlerAdapter로 위임해서 처리를 요청한다.
그다음 주어진 값들로 컨트롤러에 대한 로직을 처리하는데
InvocableHandlerMethod
다음 그림이 InvocableHandlerMethod 클래스이다.
이 때, getBridgedMethod().invoke(getBean(), args); 부분이
cglibAopProxy쪽으로 조회 로직을 맡기게 되고 그 곳에서 repository에 대한 동작을 수행하다가
findById에서 못찾았을 경우에 에러를 던지게 된다.
다시 cglibAopProxy에서 요청결과에 대한 에러를 잡아서 다시 처리되는데
이것이 InvocableHandlerMethod의 catch로 넘어온다.
catch (InvocationTargetException ex) 이부분에서
RuntimeException의 인자인지를 확인한다.
NotFoundException
이 부분에서 내가 구현한 NotFoundException 의 상속도는
NotFoundException -> NoSuchElementException -> RuntimeException -> Exception 순서기 때문에
instanceof RuntimeException 으로 처리가 되게 된다.
그렇게해서 exception 객체를 담아서 DispatcherServlet 으로 넘겨주게 된다.
DispatcherServlet
이젠 디스패쳐 서블릿이 받은 에러를 처리해줄 누군가를 찾기 시작하는데
HandlerExceptionResolverComposite
이 두 개중 HandlerExceptionResolverComposite 로 처리를 진행해준다.
그렇게 해서 resolveException 메소드를 실행해주는데
다음 이미지를 보게되면 resolvers에 3개가 들어있게 된다.
그 리졸버들이 바로 HandlerExceptionResolver 들을 구현한것들
그중에서도 나는 ResponseStatusException을 날려준게 아니기 때문에
그중에서 최종적으로 HandlerExceptionResolver 인터페이스 구현체인
ExceptionHandlerExceptionResolver, ResponseStatusExceptionResolver, DefaultHandlerExceptionResolver
세개를 가지고 for문을 돌게 된다
InvocableTargetException 이라는 객체의 target
즉, 대상이 어떤 Exception이냐에 따라서 Exception 에맞는 @ExceptionHandler로 파싱되어 커스텀된 응답으로 나가게 된다.
마무리
음 똑같은 로직 이라고 가정했을때 미묘하게 최적화를 하고싶다? 한다면
HandlerExceptionResolver 리스트의 맨앞인 ExceptionHandlerExceptionResolver를 사용 그러니까
커스텀으로 @ExceptionHandler 를 만들어 쓰는것이 ResponseStatusException 을 던지거나, @ResponseStatus 을 사용하는것보다
빠를 수 있겠다.
'Spring' 카테고리의 다른 글
| @Valid, @Validated 차이 (0) | 2022.08.10 |
|---|---|
| AOP (0) | 2022.08.10 |
| Spring Rest Docs 테스트로 문서화를 해보자! (0) | 2022.08.10 |
| Service Layer에 대한 생각 (0) | 2022.08.10 |