( 설명 )
부모 클래스를 따라 가면 결국 HttpServlet을 상속 받아서 사용하는 서블릿임을 알 수 있다
DispatcherServler --> FrameworkServler --> HttpServletBean --> HttpServlet
스프링 부트는 DispatcherServlet을 서블릿으로 자동 등록하면서 모든 경로에 대해 매핑
(이렇게 모든경로에 대해 매핑된 다음 우리가 지정하는 url경로에 대해 매핑된다)
서블릿이 호출되면 HttpServlet의 service()가 호출
--> FrameworkServlet에서 service()를 오버라이드 해두었기 때문에 이를 통해서 서블릿이 시작된다
--> 이를 통해서 DispatcherServlet.doDispatch()가 호출되며 우리의 비즈니스 로직이 시작
(결국 스프링 MVC의 핵심 동작은 DispatcherServlet.doDispatch()에 모두 기술)
( DispatcherServlet.doDispatch() )
DispatcherServlet.doDisaptch() 핵심 동작 코드
(예외처리 / 인터셉터 기능은 제외한 간단한 로직만 정리)
protected void doDispatch(HttpServletRequest request, HttpServletResponseresponse) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
ModelAndView mv = null;
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
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();
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
view.render(mv.getModelInternal(), request, response);
}
- 동작 순서

- 핸들러 조회 :
핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회
- 핸들러 어댑터 조회 :
핸들러를 실행할 수 있는 핸들러 어댑터 조회
- 핸들러 어댑터 실행 :
핸들러 어댑터를 통해 실제 핸들러를 호출해서 실행
- ModelAndView 반환 :
핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환
- viewResolver 호출 & 실행 :
뷰 리졸버를 찾고 실행해서 view 반환
- 뷰 렌더링
( 인터페이스 )
- 인터페이스 살펴보기
- 지금까지 설명한 대부분을 확장 가능한
인터페이스로 제공한다
스프링 MVC의 강점은 DispatcherServlet 코드 변경 없이 원하는 기능을 변경하거나 확장 가능한 것
인터페이스만 구현해서 DispatcherServlet에 등록하면 나만의 컨트롤러를 만들 수도 있다
(만들일은 거의 없음)
- 주요 인터페이스
- 핸들러 매핑 :
org.springframework.web.servlet.HandlerMapping
- 핸들러 어댑터 :
org.springframework.web.servlet.HandlerAdapter
- 뷰 리졸버 :
org.springframerwork.web.servlet.viewResolver
- 뷰 :
org.springframerwork.web.servlet.View
( 정리 )
스프링 MVC는 복잡해서 내부 핵심 구조만 잘 알고 있어도 충분
--> 직접 기능을 확장하거나 나만의 컨트롤러를 만들 일은 거의 없기 때문
--> 이미 수 많은 기능이 개발되어있기 때문에 필요한 거의 모든 것이 이미 존재
스프링 MVC의 핵심 구조를 알아야 향후 문제가 발생했을 때 어떤 부분에서 발생했는지 파악이 가능
( 개요 )
스프링 MVC의 구조에서 핵심적인 역할을 하는 것은 크게 3가지
- 핸들러 매핑 :
url에 해당하는 핸들러를 조회
- 핸들러 어댑터 :
핸들러를 처리할 수 있는 핸들러 어댑터 (실제 핸들러 호출)
- 뷰 리졸버 :
논리이름을 파일의 실제 물리주소로 변환
- 이 중
핸들러 매핑 / 핸들러 어댑터가 스프링 MVC에서 어떻게 구체적으로 동작하는지 이해해보자
지금은 사용하지 않는 인터페이스를 통해 내부 동작 흐름을 쉽게 이해할 수 있다
( 핸들러 매핑 / 핸들러 어댑터 동작 이해 ) - Controller 인터페이스를 활용

지금은 사용하지 않는 Controller라는 인터페이스를 상속한 OldController가 호출되는 과정을 알아보자
- 우선 해당
핸들러(컨트롤러)가 호출되려면 2가지가 필요
- HandlerMapping(핸들러 매핑)
: 해당 url 경로를 처리할 수 있는 핸들러 매핑을 찾고 해당하는 핸들러 반환
ex) 스프링 빈의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑이 필요
- HandlerAdapter(핸들러 어댑터)
: 핸들러 매핑을 통해서 찾은 핸들러를 실행할 수 있는 핸들러 어댑터가 필요
ex) Controller 인터페이스를 실행할 수 있는 핸들러 어댑터를 찾고 실행
- HandlerMapping / HandlerAdapter
처리 우선순위
0 = RequestMappingHandlerMapping
1 = BeanNameUrlHandlerMapping
...
0 = RequestMappingHandlerAdapter
1 = HttpRequestsHandlerAdapter
2 = SimpleControllerHandlerAdapter
...
- 동작 순서
- 핸들러 매핑 찾기 & 핸들러 반환
HandlerMapping을 순서대로 실행해서 실행할 수 있는 핸들러 매핑을 찾아야 함
- 이 경우
빈(Bean) 이름으로 핸들러를 찾아야 하기 때문에 BeanNameUrlHandlerMapping을 찾음
(HandlerMapping 처리 우선순위에서 1 에 해당)
- 찾은 핸들러인
OldController를 반환
- 핸들러 어댑터 조회
HnadlerAdapter의 supports()를 순서대로 호출하며 처리할 수 있는 핸들러 어댑터를 찾음
- 이 경우에
SimpleControllerHandlerAdapter가 Controller 인터페이스를 지원하므로 대상이 됨
(HandlerAdapter 처리 우선순위에서 2 에 해당)
- 핸들러 어댑터 실행
- 위에서
찾은 핸들러 어댑터인 SimpleSontrollerHandlerAdapter를 통해 실제 OldController 실행
ModelAndView 객체를 반환
( 뷰 리졸버 - viewResolver )
논리 뷰 이름을 통해서 실제 물리 주소로 매핑해주는 역할
스프링 부트가 자동 등록하는 뷰 리졸버
0 = BeanNameViewResolver
1 = InternalResourceViewResolver
스프링 부트는 JSP 사용을 위해 InternalResourceViewResolver라는 뷰 리졸버를 자동으로 등록
application.properties에 prefix / suffix설정 정보를 사용해서 등록해야 함
- spring.mvc.view.prefix :
/WEB-INF/views
- spring.mvc.view.suffix :
.jsp