ExceptionHandler_언제_어떻게
@ExceptionHandler: 언제 어떻게 동작하는가.
-
@RequestParam이나 @Pathvariable, @RequestBody 등 요청 파라미터를 매핑하는 과정에서 에러가 발생했을 시, 즉 Controller에서 @RequestMapping 메소드가 실행되기전에 에러가 발생해도도 ExceptionHandler가 동작할까?
- ex)
@RequestParam int a일 때, a에 String 값을 넘기는 경우. - 결론은 동작한다.
- ex)
-
ExceptionHandler가 동작하는 부분을 찾아보기 위해 DispatcherServlet의 doDispatch() 메소드를 살펴봤다.
-
아래 메소드를 보면 try ~ catch로 묶인 부분을 보면, request에 대해 handler를 가져와 실행되는 모든 과정에서 exception이 발생하는 경우 catch절에서 잡히게된다.
- 에러가 발생하여 catch절 온다면 위임할 exception을 담아둔다.
-
-
마지막으로 processDispatchResult에서 핸들러 메소드 실행 결과를 처리한다.
protected void doDispatch(HttpServletRequest req, HttpServletResponse res) {
try {
processedRequest = checkMultipart(req);
multipartRequestParsed = (processedRequest != req);
// 매핑가능한 handler 가져오기
mappedHandler = getHandler(processedRequest);
...
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
// preInterceptor 실행
if (!mappedHandler.applyPreHandle(processedRequest, res)) {
return;
}
// handler 실행
mv = ha.handle(processedRequest, res, mappedHandler.getHandler());
...
applyDefaultViewName(processedRequest, mv);
// postInterceptor 실행
mappedHandler.applyPostHandle(processedRequest, res, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 핸들러 메소드의 실행 결과 처리
processDispatchResult(processedRequest, res, mappedHandler, mv, dispatchException);
}
- processDispatchResult 메소드에서는 에러가 발생했을때 담아둔 exception이 있는지 확인하고, 있으면 processHandlerException() 메소드에서 처리한다.
private void processDispatchResult(
HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler,
@Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 실제 Exception 처리
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
...
}
- processHandlerException() 에서는 등록된 `this.handlerExceptionResolvers`에 따라 결과를 반환한다.
- 기본적으로 등록되어있는 `this.handlerExceptionResolvers`는 ExceptionHandlerResolver / ResponseStatusExceptionResolver / DefaultHandlerExceptionResolver가 있다.
protected ModelAndView processHandlerException(
HttpServletRequest req, HttpServletResponse res,
@Nullable Object handler, Exception ex) throws Exception {
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver exceptionResolver : this.handlerExceptionResolvers) {
exMv = exceptionResolver.resolveException(req, res, handler, ex);
if (exMv != null) {
break;
}
}
}
...
}
댓글
댓글 쓰기