Spring MVC 요청 처리 과정(feat. Servlet Container)

yuKeon·2024년 3월 28일
0
post-thumbnail

1. Spring MVC

Spring Web MVC는 서블렛 API 기반의 웹 프레임워크로, 다른 프레임워크와 마찬가지로 중앙 서블릿인 DispatcherServlet이 요청 처리를 담당하는 프론트 컨트롤러 패턴으로 구성된다. DispatcherServlet이 요청 처리의 책임을 지지만 실제 처리는 역할에 따라 컴포넌트에 위임한다. 따라서, Spring MVC의 요청 처리 흐름을 이해하기 위해서는 DispatcherServlet의 이해가 선행되어야 한다.

2. DispatcherServlet

DispatcherServlet은 요청을 순서에 따라 컴포넌트에 처리를 위임한다. DispatcherServlet도 서블릿 컨테이너가 관리하는 서블릿의 하나다. 이는 DispatcherServlet의 상속 관계를 통해 확인할 수 있다. 상속 관계는 다음과 같다.

따라서, 다른 서블릿과 마찬가지로 자바 설정파일이나 web.xml을 통한 서블릿 명세에 따라 호출, 매핑되고 서블릿 컨테이너가 생명 주기를 관리한다.

다음 그림은 서블릿의 생명 주기를 보여준다.

다음 코드는 자바로 DispatcherServlet로 등록하는 코드다.

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletCxt) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
        ac.refresh();

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

다음과 같이 web.xml 파일에 작성할 수도 있다.

<web-app>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/app-context.xml</param-value>
	</context-param>

	<servlet>
		<servlet-name>app</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value></param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>app</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>

</web-app>

위 두 예제는 Spring을 기준으로 필요한 작업이다. Spring Boot를 사용하면 자체 내장된 서블릿 컨테이너(톰켓)가 서블릿과 필터를 등록한다.

2.1 계층 구조

DispatcherServlet은 구성을 위해 WebApplicationContext가 필요하다. 서블릿은 하나의 WebApplicationContext를 포함하고, 여러 서블릿에서 공유해서 사용하는 서비스와 리포지토리와 같은 인프라 빈은 Root WebApplicationContext에포함된다.

2.2 Spring MVC 요청 처리 과정

DispatcherServlet은 다음의 순서로 요청을 처리한다.

  1. 요청이 DispatcherServlet에 들어오면 해당 요청을 처리하기 위한 핸들러를 찾기 위해 HandlerMapper에 요청을 위임한다.
  2. HandlerMapper가 핸들러를 반환하면 해당 핸들러를 실행하기 위한 HandlerAdapter를 찾는다.
  3. HandlerAdapter를 통해 핸들러를 실행한다.
  4. HandlerAdapter가 실행 결과로 ModelAndView를 반환한다.
  5. ModelAndViewViewResolver로 전달하여 뷰로 변환한다.
  6. View를 화면에 랜더링하면서 처리가 끝난다.

3. Servlet Container

서블릿 컨테이너는 서블릿의 생명 주기를 관리한다.
서블릿의 생명 주기는 init() → service() → destroy() 순서로 진행된다. 스프링에서는 서블릿 컨테이너 역할을 Tomcat이 맡고 있다.
따라서, 톰캣을 Servlet Container로 볼 수 있다.

서블릿 컨테이너는 서블릿의 생명 주기 관리 뿐만 아니라 요청이 들어왔을 때 요청을 처리하기 위한 서블릿 인스턴스를 생성하고 이를 싱글톤으로 관리한다. 또한, 다수의 요청을 멀티 쓰레드로 처리하도록 지원한다.

4. 전체 요청 처리 과정

4.1 서버 실행

  1. 톰캣 내장 서버(Web Server)를 초기화한다.
  2. Root WebApplicationContext를 로딩한다.
  3. 톰캣 내장 서버를 실행한다.

4.2 요청 처리

  1. 클라이언트가 웹 서버로 요청을 보낸다.
  2. 동적 요청의 경우 서블릿 컨테이너로 전달된다. (정적 요청의 경우 즉시 반환)
  3. 서블릿 컨테이너가 요청당 쓰레드를 생성한다.
  4. DispatcherServlet이 초기화 되지 않았다면 init() 메서드로 생성한다.
  5. 쓰레드가 DispatcherServlet의 service() 메서드를 호출한다.
  6. 2.2 Spring MVC 요청 처리 과정이 수행된다.

Ref.

0개의 댓글