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; } } } ... }
댓글
댓글 쓰기