왜 HandlerExceptionResolver에서 ModelAndView를 null로 하면 에러가 그대로 진행되고, 빈 ModelAndView를 생성하면 예외가 처리되는지 코드를 한번 열어봤습니다.
궁금하실 분도 있을 것 같아서 글 남깁니다.
아래는 DispatcherServlet의 processHandlerException 메소드 입니다.
@Nullable
protected 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 등록, 로깅 등의 처리를 하는 것을 볼 수 있습니다.
이처럼 코드를 열어보니 설명해주신 내용에 대해 더 이해가 잘 되는 것 같아 이렇게 글로 남겨서 공유합니다!
명아주님 공유 감사합니다^^
답글