티스토리 뷰


< 출처 : http://tongtechspot.blogspot.kr/2009/12/spring-mvc-tutorial.html >


위 그림에서 볼 수 있듯이 스프링의 DispatcherServlet은 MVC 모델에서 Front Controller 역할을 담당한다. 이번 글에서는 이러한 DispatcherServlet이 과연 내부적으로 어떻게 작동하여 Front Controller로서 역할을 수행하는지 분석해보자.




< Dispatcher Servlet 내부의 요청 처리 과정 >


위 그림은 Dispatcher Servlet이 요청을 받았을 때 내부적으로 어떻게 처리하는지를 보여준다. 전체적인 흐름은 요청을 받은 후 요청에 대해서 몇 가지 분석 및 필요 정보를 추출하는 요청 선처리 작업을 수행하고 Handler ExecutionChain을 매칭하여 실행 한 후 예외가 없다면 뷰 렌더링을 통해 요청에 대한 처리를 마친다.


조금 더 큰 흐름으로 보았을 때 요청이 왔다면 Hander ExecutinChain 처리 후 뷰를 렌더링 하는 방식이다.


이제 각 파트를 조금 더 자세히 들여다 보도록 하자.


  요청 선처리 작업



최초 Dispatcher Servlet에 요청이 들어오면 바로 Handler를 찾고 실행하는 것이 아니라 몇가지 선행 처리 작업을 거친다. 이 때 행해지는 일은 다음과 같다.


1) 요청에 해당하는 Locale을 결정하고 노출한다.


  - org.springframework.web.servlet.LocalResolver를 이용해서 java.util.Locale을 결정하고 노출한다.


2) 결정된 Locale을 RequestContextHolder에 저장한다.


  - org.springframework.web.context.request.RequestContextHolder에 저장하고 노출한다. 이러한 과정의 이유는 프레임워크의 코드가 단계마다 요청 정보를 넘겨받지 않고 손쉽게 요청 정보를 얻기 위해서다.


3) FlashMapManager를 통해 FlashMap을 생성한다.


  - org.springframework.web.servlet.FlashMapManager를 통해 org.springframework.web.servlet.FlashMap을 생성한다.


4) 멀티파트 요청인지 확인하고 맞다면 MultipartResolver로 해당 요청을 MultipartHttpServletRequest로 감싼다.


  - 해당 요청이 멀티파트 HTTP 요청(파일 업로드 시 요청 타입)인지 체크한다. 맞다면 org.springframework.web.multipart.MultipartResolver가 해당 요청을 org.springframework.web.multipart.MultipartHttpServletRequest로 감싼다.


5) HandlerExecutionChain 결정 단계로 넘어간다.



  HandlerExecutionChain 결정



선처리 작업을 통해 몇 가지 셋팅을 맞춘 요청에 해당하는 HandlerExecutionChain을 찾아 결정한다.


1) HandlerMapping으로 핸드러를 찾고 HandlerExecutionChain을 리턴 받는다.


  - org.springframework.web.servlet.HandlerMapping 구현체를 통해 해당하는 핸들러를 찾는다. 찾게 된다면 HandlerMapping은 org.springframework.web.servlet.HandlerExecutionChain을 리턴해준다.


2) 핸들러를 못 찾을 경우 HTTP 404 응답을 클라이언트에 전달하며 요청을 끝낸다.


3) 핸들러를 찾을 경우 HandlerAdapter를 찾고 결정한다.


  - 핸들러를 제대로 찾아서 HandlerExecutionChain을 리턴 받은 경우, 실제로 핸들러를 실행하기 위해 org.springframework.web.servlet.HandlerAdapter를 찾는다.


4) HandlerAdapter를 못 찾을 경우 ServletException을 발생시키고 요청을 끝낸다.


5) HandlerAdapter를 찾을 경우 HandlerExecutionChain 실행 단계로 넘어간다.



  HandlerExecutionChain 실행



결정된 HandlerExecutionChain을 실제로 실행한다.


1) HandlerInterceptor 구현체를 통해 preHandle을 처리한다.


  - org.springframework.web.servlet.HandlerInterceptor 구현체를 참조해서 preHandle로 처리할게 있는지 확인한다. 있다면 preHandle을 호출해서 처리하고 계속 요청 처리를 수행할지 결정한다. 요청 처리가 결정되면 다음 단계로 넘어간다.


2) HandlerAdapter를 통해 핸들러를 실행한다.


  - 앞서 찾았던 HandlerAdapter를 통해 핸들러를 실행을 위임한다. 이 때 HandlerAdapter는 핸드러를 실행하고 응답내용을 ModelAndView로 변환 및 리턴한다.


3) 리턴된 ModelAndView에 뷰가 없을 경우 RequestToViewNameTranslator가 요청을 참조해서 뷰 이름을 결정


  - 리턴된 ModelAndView에 뷰가 없을 경우, org.springframework.web.servlet.RequestToViewNameTranslator가 요청을 참조해서 뷰 이름을 결정하고 다음 단계인 postHandle 처리로 넘어간다.


4) 리턴된 ModelAndView에 뷰가 있을 경우 인터셉터의 postHandle을 처리한다.


  - 처음 인터셉터에서 preHandle을 처리 한 것 처럼 postHandle을 처리한다.


5) (요청을 처리하는 중간에) 예외가 있다면 예외 처리단계로 넘어간다. 없다면 뷰 렌더링 단계로 넘어간다.


  예외 처리



요청을 처리하는 동안 예외가 발생했을 경우 예외 처리를 해준다.


1) HandlerExceptionResolver를 통해 예외 처리에 대해 문의한다.


  - org.springframework.web.servlet.HandlerExceptionResolver에게 예외 처리 방법을 물어본다. 이 리졸버는 해당하는 예외에 맞는 뷰를 ModelAndView 형태로 리턴해준다.


2) HandlerExceptionResolver가 적당한 뷰를 리턴하지 못한 경우 예외를 다시 던진다.


  - 적당한 뷰를 못 찾을 경우 예외를 다시 던져서 서블릿 컨테이너가 처리하게 한다. 보통 이 경우 서블릿 컨테이너는 HTTP 500 응답 코드(내부 서버 오류)를 내보낸다.


3) HandlerExceptionResolver가 적당한 뷰를 리턴할 경우 다음 단계인 뷰 렌더링을 넘어간다.



  뷰 렌더링



예외가 발생하였다면 예외 처리 과정을 거치고 왔을 것이고, 아니라면 핸들러가 실행된 이후에 왔을 것이다. 이번 단계에서는 핸들러가 실행되고 나서 받은 응답으로 결정된 뷰를 분석하고 렌더링 하게 된다.


1) 결정된 뷰가 String을 참조하는지 체크한다.


  - 결정된 뷰가 java.lang.String을 참조하는지 체크한다.


2) String을 참조 할 경우 ViewResolver에게 View 구현체를 갖고오게 한다.


  - String을 참조 할 경우 미리 등록된 org.springframework.web.servlet.ViewResolver에게 실제 org.springframework.web.servlet.View 구현체를 갖고 오게 요청한다.


3) 위 과정을 거친 후 View 구현체가 존재 하지 않을 경우, ServletException을 던진다.


  - 위 과정을 거친 후 View 구현체가 존재 하지 않을 경우, javax.servlet.ServletException을 던진다.


4) 위 과정을 거친 후 View 구현체가 존재 할 경우, View 구현체를 통해 렌더링 한다.


5) 요청 처리 종료 단계로 넘어간다



  요청 처리 종료



각 요청은 예외 발생 유무와 상관없이 무조건 요청 처리 종료 과정을 거친다.


1) Handler ExecutionChain이 존재하면, 인터셉터의 afterCompletion 메소드를 실행한다.


  -Handler ExecutionChain이 존재하면, 인터셉터의 afterCompletion 메소드를 실행한다. 단, preHandle 메소드를 성공적으로 호출한 인터셉터만 afterCompletion 메소드를 호출 할 수 있다. afterCompletion 메소드 호출은 preHandle 메소드 호출 순서와 반대로 진행된다. 이러한 방식은 첫 번째로 호출된 필터가 가장 마지막에 호출되는 서블릿 필터 호출 순서 방식과 유사하다.


2) Handler ExecutionChain이 존재하지 않거나, 인터셉터의 afterCompletion 메소드가 실행 된 후, RequestHandledEvent가 발생한다.


  - Handler ExecutionChain이 존재하지 않거나, 인터셉터의 afterCompletion 메소드가 실행 된 후, org.springframework.web.context.support.RequestHandledEvent가 발생한다. 만약 org.springframework.context.ApplicationListener를 구현해 이를 빈으로 등록하면 이 이벤트를 받을 수 있고 로깅도 할 수 있다.





댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함