이전에 글들을 보면 Front-Controller라고 해서 우리가 직접 MVC구조를 하나씩 수정해가면서 만들어왔다. 그렇다면 이제는 실제 SPRING MVC구조와 우리가 직접 만든 MVC의 구조를 비교해보자.
그림에서 보면 알 수 있듯이 구조는 똑같다. 단지 이름에서 차이가 있을 뿐이다.
우리가 만든 MVC에서 가장 중요했던 Front-Controller는 SPRING MVC에서 Dispatcher Servlet이라는 이름으로 되어있는지 역시 마찬가지로 이 Dispatcher Servlet이 SPRING MVC의 핵심이라고 할 수 있다. 이 핵심같은 디스패처 서블릿은 많은 상속을 받고 있는데 그중에 하나가 우리가 사용한 HttpServlet이다.
DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet
DispatcherServlet은 부모인 FrameworkServlet 안에는 serivce()가 오버라이드 되어있고, service()를 호출하면서 많은 메서드들이 호출이 되는데 그중 가장 중요한 호출은 DispacherServlet.doDispatch() 메서드이다. 한번 해당 코드를 분석해보자.
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);
}
해당 코드들에서 호출되는 다른 메서드들도 같이 바로 아래 넣어서 보기가 편하다.
코드를 하나씩 보게 되면 우리가 만든 Front-Controller와 거의 흡사하다는걸 알 수 있다. 몇가지 처음보는 코드가 있는데 스프링이 알아서 처리해주는 로직이라 굳이 지금 신경쓸 필요는 없다.
하나씩 분석해보면
- 핸들러 조회 : 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.
- 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.
- 핸들러 어댑터 실행: 핸들러 어댑터를 실행한다.
- 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행한다.
- ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.
- viewResolver 호출: 뷰 리졸버를 찾고 실행한다.
JSP의 경우: InternalResourceViewResolver 가 자동 등록되고, 사용된다. - View 반환: 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환한다.
JSP의 경우 InternalResourceView(JstlView) 를 반환하는데, 내부에 forward() 로직이 있다. - 뷰 렌더링: 뷰를 통해서 뷰를 렌더링 한다.
우리가 했던 순서 그대로인걸 알 수 있다.
우리는 모든 준비물을 직접 만들었지만 spring에서 제공해주는 인터페이스를 보자.
- 핸들러 매핑: org.springframework.web.servlet.HandlerMapping
- 핸들러 어댑터: org.springframework.web.servlet.HandlerAdapter
- 뷰 리졸버: org.springframework.web.servlet.ViewResolver
- 뷰: org.springframework.web.servlet.View
지금 간략하게 당장 우리가 만들었던 구조에 빗대어 소량의 코드와 인터페이스를 봤지만 실제로 스프링 안에는 다 확인하지도 못할 만큼의 코드들이 존재한다. 우리는 그걸 다 이해할 필요도 없을 만큼 존재한다. 하지만 위에서 간략한 코드 분석을 한 이유는 우리가 개발을 하면서 문제가 생겼을 때 어느정도 문제를 이해할 수 있고 확장이 필요할 때 어느 부분에서 수정이 필요한지 알 수 있는데 도움이 되서이다.
이번 글에서는 우리가 만든 Front-Controller에 빗대어 큰 그림을 보았다. 다음 글에서는 좀 더 자세히 알아야하는 Handler와 HandlerAdapter를 자세히 알아보자.
'spring' 카테고리의 다른 글
뷰 리졸버 (0) | 2023.03.21 |
---|---|
HandlerMapping, HandlerAdapter (0) | 2023.03.20 |
Front-Controller 정리 (0) | 2023.03.19 |
Front Controller (5-1) (0) | 2023.03.19 |
Front Controller (5) (0) | 2023.03.19 |