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()

설계 의도 및 이유

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

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