처음 요청을 처리하는 곳은 DispatcherServlet 이다
HTTP 요청을 택배로 비유한다면 DispatcherServlet 는 물류센터에 비유할 수 있다. “(특별한 요청을 위해)보내다”라는 의미의 Dispatch 라는 단어가 붙은 대로 DispatcherServlet은 HTTP 요청을 처리하는 담당 클래스(= 핸들러)에게 HTTP 요청을 보내는 역할을 한다. Spring MVC 는 HttpServlet 을 이용해 클라이언트의 요청을 처리해 응답한다. DispatcherServlet은 Spring이 HttpServlet 을 구현한 구현체다.
DispatcherServlet이 처리해야 하는 작업들
우리가 @Controller 혹은 @RestController 어노테이션을 이용해 만든 컨트롤러에게 HTTP 요청의 처리를 위임해야 한다. 이를 위해선 다음 작업들이 수행되어야 한다.
1.
어떤 컨트롤러 객체를 사용해야 하는지 결정
2.
어떤 메서드를 사용해야 하는지 결정
3.
메서드를 호출하기 위한 매개변수 생성
4.
메서드의 반환값을 HTTP 응답에 적절히 표현
어떤 컨트롤러 객체를 사용해야 하는지 결정 : HandlerMapping
컨트롤러의 인스턴스는 Spring이 시작되면서 복잡한 과정을 통해 생성되어 Spring 컨테이너 내부에서 관리된다.
즉, 컨트롤러 객체는 이미 존재한다.
이 많은 컨트롤러 객체 중 어떤 컨트롤러 객체를 사용해야 하는지 결정하는 것이 HandlerMapping 이다.
HandlerMapping 은 인터페이스로 Spring과 Spring Boot 내부에 여러 구현체가 있다.
어떤 컨트롤러 객체라도 실행할 수 있도록 하기 위한 인터페이스 : HandlerAdapter
우리가 작성한 컨트롤러는 어떤 인터페이스를 구현해야 한다는 등의 제약 조건이 없다. 따라서, Spring이 우리가 작성한 컨트롤러를 실행하기 위해서는 우리가 작성한 컨트롤러 클래스와 Spring이 생각하는 핸들러 사이의 간극을 처리할 무언가가 필요하다.
이를 위해 Spring은 Adapter 패턴을 채택했다. 즉, 컨트롤러를 만들거면, 이를 처리할수 있도록 HandlerAdapter도 만들어야 한다. 다만, 우리는 Spring이 제공하는 어노테이션을 사용했기 때문에 기본적으로 만들어져있는 HandlerAdapter가 우리의 Controller를 실행할 수 있다.
이렇게 적절한 HandlerAdapter 를 찾았다면 DispatcherServlet 이 HandlerAdapter 를 이용해 핸들러를 실행한다.
그리고 HandlerAdapter 내부에서 적절한 메서드와 매개변수를 찾아 실행한다. HandlerMethodArgumentResolver 를 이용해 매개변수를 생성한 뒤, ServletInvocableHandlerMethod를 이용하여 메서드를 호출하고, HandlerMethodReturnValueHandler 를 이용해 메서드의 반환값을 처리한다.
그리고 그 실행 결과를 ModelAndView 형태로 반환한다.
메서드의 반환값을 HTTP 응답에 적절히 표현
사실, 정확히 말하면 메서드의 반환값을 HTTP 응답에 표현한다기보단, 그 반환 값을 이용해 표현할 내용을 작성한다고 봐야 한다.
@Controller
@RequestMapping("/admin")
public class AdminPageController {
@GetMapping
public String mainPage() {
return "admin/index";
}
}
Java
복사
위와 같은 컨트롤러를 작성했다면, HTTP 응답에 표현되어야 하는 것은 templates/admin/index.html 파일이다. 이를 위해 ModelAndView 를 사용한다. ModelAndView 에는 이런 html 에 대응하는 View의 이름을 가지고 있다.
적절한 View 를 찾는 역할 : ViewResolver
이런 View 의 이름으로부터 적절한 View 객체를 찾는 역할을 ViewResolver 가 수행한다.
그렇게 View를 찾으면, View.render 메서드가 수행된다.
그림으로 보자
앞서 정리한 내용을 이해하기 쉽게 그림으로 그려보았다.
Http 요청이 Controller에서 처리되는 과정
1.
Servlet Engine이 요청과 응답을 처리하는 HttpServletRequest와 HttpServletResponse 객체를 생성해 DispatcherServlet으로 전달한다.
2.
DispatcherServlet은 HandlerMapping을 이용해 적절한 Handler를 찾는다.
3.
DispatcherServlet이 적절한 HandlerAdaptor를 찾아 Handler 의 실행을 위임한다.
4.
HandlerAdaptor는 HandlerMethodArgumentResolver 을 이용해 메서드 실행을 위한 매개변수를 찾는다.
5.
HandlerAdaptor는 메서드 실행을 ServletInvocableHandlerMethod에 위임한다.
6.
ServletInvocableHandlerMethod은 Controller의 메서드를 실행한다.
7.
Controller가 반환한 값을 처리할 수 있는 HandlerMethodReturnValueHandler 를 찾아 처리한다.
8.
ModelAndView 를 생성한다.
9.
ModelAndView 를 DispatcherServlet에 응답한다.
10.
ViewResolver를 이용해 적절한 View 를 찾아온다.
11.
View 에 ModelAndView 의 Model 을 랜더링 한다.
12.
Servlet Engine이 HttpServletResponse 를 이용해 적절히 Http 응답을 보낸다.