스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
왜 null을 반환하면 계속 진행되고, null 이 아니면 예외를 처리하는지 확인해봤습니다
왜 HandlerExceptionResolver에서 ModelAndView를 null로 하면 에러가 그대로 진행되고, 빈 ModelAndView를 생성하면 예외가 처리되는지 코드를 한번 열어봤습니다.
궁금하실 분도 있을 것 같아서 글 남깁니다.
아래는 DispatcherServlet의 processHandlerException 메소드 입니다.
@Nullableprotected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception { // Success and error responses may use different content types request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); // Check registered HandlerExceptionResolvers... ModelAndView exMv = null; if (this.handlerExceptionResolvers != null) { for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) { exMv = resolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } } if (exMv != null) { if (exMv.isEmpty()) { request.setAttribute(EXCEPTION_ATTRIBUTE, ex); return null; } // We might still need view name translation for a plain error model... if (!exMv.hasView()) { String defaultViewName = getDefaultViewName(request); if (defaultViewName != null) { exMv.setViewName(defaultViewName); } } if (logger.isTraceEnabled()) { logger.trace("Using resolved error view: " + exMv, ex); } else if (logger.isDebugEnabled()) { logger.debug("Using resolved error view: " + exMv); } WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } throw ex;}
이 전체코드에서 우리가 구현한 resolveException 처리하는 부분만 떼보면
// Check registered HandlerExceptionResolvers...ModelAndView exMv = null;if (this.handlerExceptionResolvers != null) { for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) { exMv = resolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } }}
이렇게 됩니다. 코드를 열어보니 정말 간단하게도 exMv를 null로 초기화해놓고 등록된 resolver들을 돌면서 resolveException을 호출하여 결과가 null 이 아니면 break하는 것을 볼 수 있습니다.
이렇게 만들어진 exMv(모델앤뷰)가 null 이면 (모든 HandlerExceptionResolver 를 다 돌고도 null)
아래의 if문
if (exMv != null) { if (exMv.isEmpty()) { request.setAttribute(EXCEPTION_ATTRIBUTE, ex); return null; } // We might still need view name translation for a plain error model... if (!exMv.hasView()) { String defaultViewName = getDefaultViewName(request); if (defaultViewName != null) { exMv.setViewName(defaultViewName); } } if (logger.isTraceEnabled()) { logger.trace("Using resolved error view: " + exMv, ex); } else if (logger.isDebugEnabled()) { logger.debug("Using resolved error view: " + exMv); } WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv;}throw ex;
조건에 걸리지 않아 throw ex;로 에러를 던지게 됩니다.
exMv가 null이 아니면 exMv의 여러 상태에서 따라 request에 attribute를 설정하거나, viewName 등록, 로깅 등의 처리를 하는 것을 볼 수 있습니다.
이처럼 코드를 열어보니 설명해주신 내용에 대해 더 이해가 잘 되는 것 같아 이렇게 글로 남겨서 공유합니다!