Spring MVC는 프론트 컨트롤러 패턴을 따릅니다.
HTTP 요청이 들어오면 DispatcherServlet이라 불리는 프론트 컨트롤러가 모든 요청을 받고, 이 서블릿을 중심으로 애플리케이션이 작동합니다.
아래 코드는 DispatcherServlet의 주요 메서드 들입니다.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
// 1. 핸들러 조회
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2. 핸들러 어댑터 조회 - 핸들러를 처리할 수 있는 어댑터
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. 핸들러 어댑터 실행 -> 4. 핸들러 어댑터를 통해 핸들러 실행 -> 5. ModelAndView 반환
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
processDispatchResult(processedRequest, response, mappedHandler, mv,
dispatchException);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
// 뷰 렌더링 호출
render(mv, request, response);
}
protected void render(ModelAndView mv, HttpServletRequest request,HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();
// 6. 뷰 리졸버를 통해서 뷰 찾기, 7. View 반환
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
// 8. 뷰 렌더링
view.render(mv.getModelInternal(), request, response);
}
핸들러 매핑을 통해 요청 URL에 매핑된 핸드러(컨트롤러)를 조회한다.
조회한 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.
핸들러 어댑터를 실행한다.
어탭터가 컨트롤러를 실행한다. (로직 실행)
핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.
ModelAndView 객체에는 Model 데이터가 담겨있고, 클라이언트에게 보내고싶은 view페이지의 논리적 이름이 담겨져있다.
ViewResolver는 논리적 view 이름을 실제 경로로 변경하고 View객체에 담아 반환한다.
(ex)
논리 뷰 이름: members
실제 뷰 경로: /WEB-INF/views/members.jsp
스프링 MVC를 공부하면서 가장 헷갈렷던 부분이 핸들러 매핑과 핸들러 어댑터였습니다.
(여기서 간단하게 정리하지만 꼭 강의를 참고하자, 참 자세하게 알려주신다.)
핸들러 매핑은 우선순위를 가지고 url을 조회합니다.
0순위 = RequestMappingHandlerMapping :
어노테이션 기반의 컨트롤러, @RequestMapping이 달린 컨트롤러중 url이 일치하는 것이 있는지 확인. 없다면 1순위로 넘어감..
1순위 = BeanNameHandlerMapping :
url과 이름이 똑같은 스프링 빈을 찾아 실행한다. 업다면 2순위로 ...
2순위 = ...
지금은 스프링에서 @RequestMapping처럼 어노테이션 기반 컨트롤러를 99%이상 사용하지만, 사실 이것 말고 어떤 파라미터를 받고 어떤 반환값을 반환할지에 따라 수많은 컨트롤러가 존재합니다.
스프링 MVC는 이 모든 컨트롤러들을 모두 사용할 수 있도록 핸들러 어댑터를 통해 같은 파라미터를 받고, 같은 반환값을 갖도록 통일시켜줍니다. (110V, 220V 콘센트 변환기와 유사한 것)
핸들러 어댑터도 핸들러 매핑과 마찬가지로 우선순위를 가지고 사용가능한 어댑터를 조회합니다.
0순위 = RequestMappingHandlerAdapter :
@RequestMapping기반으로 만들어진 컨트롤러인지확인, 아니면 1순위로..
1순위 = HttpRequestHandlerAdapter :
인터페이스인 HttpRequestHandler를 구현해 만든 컨트롤러인지, 아니면 2순위로...
2순위 = SimpleControllerHandlerAdapter :
인터페이스인 Controller를 구현해 만든 컨트롤러인지(@Controller와 다른 것, 예전에 사용하던 방식이다.), 아니면 3순위로...
3순위 = ...