Deep Dive /Java Web /8

8. FrameworkServlet → DispatcherServlet: doDispatch()

FrameworkServlet의 상위 기본 처리가 끝나면, DispatcherServlet의 doDispatch()로 실제 Spring MVC 로직이 실행되는 단계를 오픈소스 코드 근거로 분석합니다.


이번 단계의 역할

  1. FrameworkServlet.service()가 호출 (상위 클래스 기본 처리)
  2. FrameworkServlet.processRequest()에서 doService()를 호출 (템플릿 메서드 패턴)
  3. DispatcherServlet.doService()에서 doDispatch() 호출 (하위 클래스 구현)
  4. doDispatch()에서 핸들러 매핑, 인터셉터, 컨트롤러 호출 등 모든 MVC 로직 실행

핵심 코드

1) FrameworkServlet.service() → processRequest()

// FrameworkServlet.java
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    processRequest(request, response);
}

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    ...
    try {
        doService(request, response); // 템플릿 메서드: 하위 클래스에서 구현
    }
    finally {
        ...
    }
}

2) DispatcherServlet.doService() → doDispatch()

// DispatcherServlet.java
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    ...
    try {
        doDispatch(request, response); // 실제 MVC 로직 시작
    }
    finally {
        ...
    }
}

protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 1. 핸들러 매핑
            mappedHandler = getHandler(processedRequest);

            // 2. 핸들러 어댑터 획득
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // 3. 인터셉터 preHandle
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 4. 컨트롤러 호출
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            // 5. 인터셉터 postHandle
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }

        // 6. 뷰 렌더링
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    finally {
        ...
    }
}

호출 흐름 다이어그램

sequenceDiagram participant FrameworkServlet participant DispatcherServlet participant HandlerMapping participant Interceptor as HandlerInterceptor participant Controller FrameworkServlet->>DispatcherServlet: doService() DispatcherServlet->>DispatcherServlet: doDispatch() DispatcherServlet->>HandlerMapping: getHandler() HandlerMapping-->>DispatcherServlet: HandlerExecutionChain DispatcherServlet->>Interceptor: preHandle() DispatcherServlet->>Controller: handle() Controller-->>DispatcherServlet: ModelAndView DispatcherServlet->>Interceptor: postHandle()

코드 해설

이 단계에서 Spring MVC의 실제 오케스트레이션이 시작됩니다. FrameworkServlet은 템플릿 메서드 구조로 공통 요청 처리를 담당하고, DispatcherServlet.doDispatch()가 핸들러 조회·인터셉터·컨트롤러 호출·응답 렌더링까지 이어지는 전체 흐름을 주도합니다.


설계 의도

  • 템플릿 메서드 패턴: FrameworkServlet은 기본 구조(service → processRequest)를 정하고, DispatcherServlet에서 구체적 구현(doService → doDispatch)을 채움
  • 계층 분리: 상위 클래스에서 공통 처리(요청/응답 관리, 트랜잭션 처리)를 하고, 하위 클래스에서 MVC 로직(핸들러 매핑, 컨트롤러 호출)에 집중
  • 확장성: 다른 서블릿도 FrameworkServlet을 상속받아 자신의 doService()를 구현 가능

← 이전: 7. StandardWrapperValve → FrameworkServlet | 다음: 9. DispatcherServlet → HandlerMapping