스프링 부트의 spring-boot-starter-web 모듈을 사용하면 기본적으로 톰캣을 사용하는 스프링 MVC 구조를 기반으로 동작한다.
일반적인 웹 요청이들어왔을 때의 스프링 부트의 동작 구조는 아래와 같다.
서블릿(Servlet)은 클라이언트의 요청을 처리하고 결과를 반환하는 자바 웹 프로그래밍 기술이다. 그리고 이는 일반적으로 서블릿은 서블릿 컨테이너(Servlet Container)에서 관리한다. 서블릿 컨테이너는 서블릿 인스턴스(Servlet Instance)를 생성하고 관리하는 역할을 수행하는 주체로서 톰캣은 WAS의 역할과 서블릿 컨테이너의 역할을 수행하는 대표적인 컨테이너이다. 몇 가지 서블릿 컨테이너의 특징은 이러하다.
스프링에서는 DispatcherServlet이 서블릿의 역할을 수행한다. 일반적으로는 스프링은 톰캣을 임베드해 사용한다. 따라서 서블릿 컨테이너와 DispatcherServlet은 자동 설정된 web.xml의 설정값을 공유한다.
위 그림을 해석해보겠다.
1. DispatcherServlet으로 요청(HttpServletRequest)이 들어오면 DispatcherServlet은 핸들러 매핑(Handler Mapping)을 통해 요청 URI에 매핑된 핸들러를 탐색한다. 여기서 핸들러는 컨트롤러(Controller)를 의미한다.
2. 핸들러 어댑터(HandlerAdapter)로 컨트롤러를 호출한다.
3. 핸들러 어댑터에 컨트롤러의 응답이 돌아오면 ModelAndView로 응답을 가공해 반환한다.
4. 뷰 형식으로 리턴하는 컨트롤러를 사용할 때는 뷰 리졸버(View Resolver)를 통해 뷰(View)를 받아 리턴한다.
핸들러 매핑은 요청 정보를 기준으로 어떤 컨트롤러를 사용할지 선정하는 인터페이스이다.
핸들러 매핑 인터페이스의 대표적인 구현체 클래스 몇 가지를 소개해보겠다.
BeanNameUrlHandlerMapping
-> 빈 이름을 URL로 사용하는 매핑 전략이다.
-> 빈을 정의할 때 슬래시('/')가 들어가면 매핑 대상이 된다.
-> ex) @Bean("/")
ControllerClassNameHandlerMapping
-> URL과 일치하는 클래스 이름을 갖는 빈을 컨트롤러로 사용하는 전략
-> 이름 중 Controller를 제외하고 앞부분에 작성된 suffix를 소문자로 매핑한다.
SimpleUrlHandlerMapping
-> URL 패턴에 매핑된 컨트롤러를 사용하는 전략
DefaultAnnotationHandlerMapping
-> 어노테이션으로 URL과 컨트롤러를 매핑하는 방법
뷰 리졸버는 뷰의 렌더링 역할을 담당하는 뷰 객체를 반환하게 된다.
뷰가 없는 REST 형식의 @ResponseBody를 사용하게 되는 경우가 많은데, 이럴 때는 아래와 같이 뷰 리졸버를 호출하지 않고 MessageConverter를 거쳐 JSON형식으로 변환해 응답하게 된다.
MessageConverter는 요청과 응답에 대해 Body 값을 변환하는 역할을 수행한다. 스프링 부투의 자동 설정 내역을 보면 HttpMessageConverter 인터페이스를 사용한다.
※ 스프링 부트는 자동 설정을 지원하기 때문에 애플리케이션을 편리하게 개발할 수 있다. 하지만 심도 있는 개발을 위해서는 스프링의 동작 원리를 당연히 파악해야 한다. 스프링 모듈만으로 개발을 해본다면 동작 원리를 파악하는 데 큰 도움이 될 것이다.