Framework/Spring

[Spring] DispatcherServlet이 뭘까?

KOOCCI 2022. 8. 16. 22:34

목표 : DispatcherServlet에 대해 설명할 수 있다.


SpringMVC에 대해 처음 설명하는 사항이 DispatcherServlet이다.

대체 무엇이길래 제일 처음부터 설명하는 것일까?

 

DispatcherServlet

SpringMVC는 Spring Framework에 최초부터 들어있던 Servlet API 기반의 웹 프레임워크다.

우선 한번 복습해보자.

 

Servlet

Servlet : 정적인 HTML의 한계를 극복하고 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양

Servlet Container : Servlet Interface의 구현체로서, Servlet의 LifeCycle(Init, Destroy, Service)을 구현하고 있으며 구동 환경을 제공하여 Servlet을 관리. (Apache Tomcat, Jeus 등)

Servlet Container 구동 순서

  1. Servlet Container가 시작 시, 모든 Servlet을 가지고 있는다.
  2. Client로부터 요청이 들어왔을 때, Request(HttpServletRequest)와 Response(HttpServletResponse) Instance 를 생성한다.
  3. 요청 URL을 분석하여, 어떤 Servlet이 담당인지 찾고, 해당 Servlet의 쓰레드에 Request와 Response 객체를 전달한다.
    1. Servlet의 Service() 메서드를 호출해, Request와 Response를 전달하고 메소드에 따라 doGet, doPost등을 호출한다.
    2. 해당 메서드에서response에 응답내용을 넣는다.
  4. Servlet Container는 Response를 Client에게 전달하고, Request와 Response를 소멸시킨다.
  5. Servlet Instance 자체는 사라지지 않고, Servlet Container가 멈추기 전까지 요청에 대한 처리를 수행한다.

Servlet 상속관계

 

DispatcherServlet

이제 Servlet이 무엇인지 알고 있으니, DispatcherServlet이 어떻게 다른지 알아볼 차례다.

공식 문서에서는 다음과 같이 표현하고 있다.

 

Spring MVC, as many other web frameworks, is designed around the front controller pattern where a central Servlet, the DispatcherServlet, provides a shared algorithm for request processing, while actual work is performed by configurable delegate components. This model is flexible and supports diverse workflows.

 

DispatcherServlet중앙 서블릿이며,요청 처리를 위한 공유 알고리즘을 제공하는 반면 실제 작업은 구성 가능한 대리자 구성 요소에 의해 수행되는 Front Controller 패턴으로 설계되었다.

 

너무 번역투이니 조금 정리해보면,

Front Controller 패턴으로 설계되어, 모든 요청처리를 가장 먼저 받고, 실질적으로 일하는 적합한 Component(Controller)에게 위임하는 역할이다.

 

DispatcherServlet은 다른 Servlet과 마찬가지로, web.xml이나 java configuration으로 선언된다.

다음과 같이 설정하면, Servlet Container에서 자동으로 찾아서 설정하게 된다.

(SpringBootServletInitializer의 경우, 내부적으로 WebApplicationInitializer를 구현하고 있는 Abstract Class다.)

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {

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

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.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>

 

왜 DispatcherServlet이 사용되었을까?

 

Web.xml에서 Servlet 매핑을 줄여주었다.

각 Servlet에 대해 요청URL과 매핑해주어야 했던 이전과 달리, DispatcherServlet이 Front Controller를 해주므로, Controller를 수현해두기만 하면, DispatcherServlet이 알아서 위임해주게 되었다.

 

공통된 처리를 할 수 있다.

인코딩, 에러 처리, 공지 등에 대한 처리를 한번에 해결할 수 있다.

 

DispatcherServlet의 흐름

그럼 전체 흐름을 한번 그려보자.

  1. 서블릿 컨테이너는 시작 시, 모든 Servlet을 가지고 있다.
  2. Client의 요청이 들어오면, 제일 먼저 DispatcherServlet이 요청을 받는다.
  3. 공통적인 작업을 먼저 DispatcherServlet이 처리한다.
  4. URL을 분석해 알맞는 Controller(Servlet)를 찾는다.
  5. 요청을 컨트롤러로 위임할 Handler mapping을 찾아서 전달한다. (Controller로 전달하려면 어떤 Mapping을 가져올지 확인)
  6. Handler Adapter를 통해 요청을 위임한다. (Mapping된 Adapter로 위임)
  7. Service 로직(Business 로직) 실행
  8. 응답 반환 (Controller -> Adapter -> DispatcherServlet)
  9. Client로 반환

Wrap up

조금 더 자세한 내용들이 많다.

파고들면 파고들수록 까다로운 Spring이다.