스프링으로 개발을 하면 가장 쉽게 접하는 개념 중 하나가 Controller 이다.
내가 처음 Controller 를 이해했을 때는 Client 로 부터 Http Request 가 전송되면 Request 정보 중 요청 주소(URI 혹은 URL) 에 따른 Controller 내부 메소드를 동작시키는 것으로 이해를 했다.
요청 주소 패턴에 대한 매핑 과정이 내부적으로 수행되고, 메소드는 비즈니스 로직을 수행하는 일련의 과정이라고 어렴풋이 예상을 하고는 있었지만 이번 기회에 한번 디테일한 동작 방식에 대해서 알아보자고 생각이 들어 자료를 조사하게 되었다.
서버 측면에서 Client 의 요청을 최초로 받는 웹서버(Apache), 이 웹서버와 소켓을 열어 통신하는 Tomcat, 또 다시 Tomcat 은 Servlet Container 로써의 역할을 수행하는데 이 Tomcat 이 Servlet 을 관리, 즉 요청 주소에 대응되는 Servlet 을 반환해줄 때 사용하는 것이 Dispatcher Servlet 이다.
Dispatcher Servlet 은 Front Controller 라고도 불리는데 그 이유는 Front Controller 패턴을 가지는 객체이기 때문이다.
기존의 요청에 대한 Controller mapping 은 servlet, servlet-mapping 구조의 web.xml 를 작성하여 구현하였는데, 아무래도 자바 외의 파일을 관리해야하는 소요가 생기고, 1대1 매칭의 한계 때문에 다소 불편한 느낌이 있었다.
이에 대한 대안으로 Dispatcher Servlet 은 자바 객체로, 서블릿 컨테이너로 들어오는 모든 요청을 전달받는다. 모든 요청에 대한 공통적인 동작을 수행하고 나서는 요청 주소에 매핑되는 컨트롤러에게 이후 동작을 위임하여야하는데 이 때 우리가 보통 작성하는 @Controller annotation 이 붙은 Controller 객체가 getBean() 을 통해 호출된다.
우리가 Controller 라고 말하는 것이 Spring Framework 에서는 Handler 라고 불리는데, 요청에 해당하는 적절한 Handler 를 찾아 작업을 수행시키는 주체가 HandlerAdapter 객체이다.
최초 스프링 프로젝트 빌드 과정에서 디스패처 서블릿이 모든 요청에 대한 컨트롤러 를 HashMap 구조로 데이터를 구성하고, 관리하는데 이 과정을 Handler Mapping 이라고 한다.
즉 Dispatcher Servlet 은 요청에 따른 컨트롤러 객체(Handler)를 HandlerAdapter 에게 제공하고, 그 이후 시점부터 이 Adapter 가 컨트롤러를 동작하고 결괏값인 ResponseEntity 를 반환합니다.
Dispatcher Servlet 이 ResponseEntity 를 반환받으면 MessageConverter가 최종적으로 응답을 처리하는데 응답에 포함된 view 를 찾아서 Controller 에 추가한 데이터와 함께 최종 Response 를 반환한다.