DispatcherServlet

szlee·2025년 1월 12일

DispatcherServlet은 Spring MVC의 핵심 컴포넌트로, 프론트 컨트롤러(Front Controller) 패턴을 구현한 클래스이다. 서블릿 필터를 거친 후의 모든 HTTP 요청을 받아 적절한 컨트롤러로 위임하는 역할을 한다.

// DispatcherServlet 내부 로직 (의사 코드)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
    // 1. 핸들러 찾기
    HandlerExecutionChain mappedHandler = getHandler(request);
    
    // 2. 핸들러 어댑터 찾기
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    // 3. 핸들러 실행
    ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
    
    // 4. 뷰 처리
    processDispatchResult(request, response, mappedHandler, mv);
}

DispatcherServlet의 주요 처리 과정

  1. 요청 접수
    클라이언트로부터 HTTP 요청이 들어오면 DispatcherServlet이 가장 먼저 요청을 받습니다.
    web.xml 또는 Java Config를 통해 URL 패턴을 지정할 수 있으며, 보통 "/"로 설정하여 모든 요청을 처리한다.

  2. 핸들러(컨트롤러) 매핑
    HandlerMapping을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.
    RequestMappingHandlerMapping이 가장 많이 사용되며, @RequestMapping 어노테이션을 통해 매핑된다.

  3. 핸들러 어댑터 조회
    해당 핸들러를 실행할 수 있는 HandlerAdapter를 조회한다.
    RequestMappingHandlerAdapter가 주로 사용되며, @RequestMapping 기반의 컨트롤러를 처리한다.

  4. 핸들러 실행
    HandlerAdapter를 통해 핸들러를 실행한다.
    컨트롤러의 비즈니스 로직이 실행되고 ModelAndView를 반환한다.

  5. 뷰 리졸버
    ViewResolver를 통해 뷰의 논리 이름을 실제 뷰 객체로 변환한다.
    예를 들어, "home"이라는 논리 이름을 "/WEB-INF/views/home.jsp"와 같은 실제 뷰 경로로 변환한다.

  6. 뷰 렌더링
    View 객체를 통해 실제 뷰를 렌더링한다.
    JSP, Thymeleaf 등 다양한 템플릿 엔진을 지원한다.

예외 처리

DispatcherServlet은 HandlerExceptionResolver를 통해 예외를 처리한다.
@ExceptionHandler, @ControllerAdvice 등을 통해 전역 예외 처리가 가능하다.

인터셉터

HandlerInterceptor를 구현하여 컨트롤러 실행 전후에 공통 로직을 수행할 수 있다.
로깅, 인증, 권한 체크 등에 활용된다.

멀티파트 처리

MultipartResolver를 통해 파일 업로드와 같은 멀티파트 요청을 처리한다.
CommonsMultipartResolver 또는 StandardServletMultipartResolver를 주로 사용한다.

DispatcherServlet의 장점

중앙 집중식 요청 처리

  • 모든 요청을 한 곳에서 처리하므로 공통 로직을 쉽게 적용할 수 있다.
  • 보안, 로깅, 인코딩 등의 횡단 관심사를 효율적으로 처리할 수 있다.

유연한 설계

  • 각 컴포넌트가 인터페이스로 정의되어 있어 커스터마이징이 용이하다.
  • 다양한 뷰 기술과 설정 방식을 지원한다.

확장성

  • 새로운 HandlerMapping, HandlerAdapter, ViewResolver 등을 추가하여 기능을 확장할 수 있다.
  • 커스텀 인터셉터와 리졸버를 통해 특별한 요구사항을 처리할 수 있다.

예외 처리

@ExceptionHandler와 @ControllerAdvice는 DispatcherServlet의 예외 처리 메커니즘의 일부이다.

예외 발생 시 처리 순서

try {
    // DispatcherServlet이 요청을 처리하는 과정
    doDispatch(request, response);
} catch (Exception ex) {
    // 예외가 발생하면 예외 처리 메커니즘으로 전달
    processHandlerException(request, response, handler, ex);
}

HandlerExceptionResolver 동작

DispatcherServlet은 기본적으로 여러 HandlerExceptionResolver를 가지고 있다.

  • ExceptionHandlerExceptionResolver (@ExceptionHandler 처리)
  • ResponseStatusExceptionResolver (@ResponseStatus 처리)
    DefaultHandlerExceptionResolver (Spring 내부 예외 처리)

예외 처리 우선순위

컨트롤러 내부의 @ExceptionHandler (가장 높음)
@ControllerAdvice 클래스의 @ExceptionHandler
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver (가장 낮음)

ExceptionHandlerExceptionResolver의 주요 기능

@ExceptionHandler 메서드 검색
예외 타입 매칭
적절한 응답 생성 (JSON, XML, 뷰 등)

이러한 예외 처리 메커니즘이 DispatcherServlet 내부에서 동작하는 이유

중앙 집중식 예외 처리가 가능
일관된 예외 처리 방식 제공
예외 처리의 재사용성 향상

DispatcherServlet이 예외 처리의 진입점 역할을 하고, 실제 처리는 각각의 HandlerExceptionResolver가 담당한다.


Spring Interceptor는 핸들러 매핑 이후, 핸들러 실행 전후에 실행된다.

  1. 클라이언트 요청 접수 (DispatcherServlet)
  2. 핸들러 매핑
  3. Interceptor의 preHandle() 실행
  4. 핸들러(컨트롤러) 실행
  5. Interceptor의 postHandle() 실행
  6. 뷰 렌더링
  7. Interceptor의 afterCompletion() 실행
  8. 응답 반환
@Component
public class LoggingInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        // 컨트롤러 실행 전 처리
        log.info("preHandle: " + request.getRequestURI());
        return true; // false를 반환하면 요청 중단
    }
    
    @Override
    public void postHandle(HttpServletRequest request, 
                         HttpServletResponse response, 
                         Object handler, 
                         ModelAndView modelAndView) throws Exception {
        // 컨트롤러 실행 후, 뷰 렌더링 전 처리
        log.info("postHandle: " + request.getRequestURI());
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, 
                              HttpServletResponse response, 
                              Object handler, 
                              Exception ex) throws Exception {
        // 뷰 렌더링 후 처리
        log.info("afterCompletion: " + request.getRequestURI());
    }
}
  • preHandle(): 컨트롤러 실행 전에 호출되며, false 반환 시 요청 처리를 중단
  • postHandle(): 컨트롤러 실행 후, 뷰 렌더링 전에 호출.
    컨트롤러에서 예외 발생 시 postHandle()은 호출되지 않음
  • afterCompletion(): 뷰 렌더링을 포함한 모든 처리가 끝난 후 호출.
    afterCompletion()은 예외가 발생하더라도 항상 호출됨

웹 애플리케이션에서 HTTP 요청이 들어왔을 때의 처리 순서

HTTP Request 
    → WAS(톰캣)
        → Filter1
            → Filter2
                → DispatcherServlet
                    → Interceptor1
                        → Interceptor2
                            → Controller
                        ← Interceptor2
                    ← Interceptor1
                ← DispatcherServlet
            ← Filter2
        ← Filter1
    ← WAS(톰캣)
← HTTP Response
  1. Filter (서블릿 필터)
@Component
public class CustomFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, 
                        ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        // DispatcherServlet 실행 전 처리
        chain.doFilter(request, response);
        // DispatcherServlet 실행 후 처리
    }
}
  1. DispatcherServlet
  • 필터 체인을 거친 후 DispatcherServlet이 실행된다.
  • web.xml 또는 Java Config에서 설정한 URL 패턴에 따라 요청을 처리한다.
  1. Interceptor
  • DispatcherServlet이 요청을 받은 후 실행된다.

Filter와 Interceptor의 주요 차이점

실행 시점

  • Filter: DispatcherServlet 이전/이후
  • Interceptor: DispatcherServlet 내부에서 컨트롤러 호출 전/후

스프링 관리 여부

  • Filter: 서블릿 컨테이너가 관리
  • Interceptor: 스프링 컨테이너가 관리

사용 용도

  • Filter: 인코딩, 보안, 인증 등 전역적인 처리
  • Interceptor: 로깅, 권한 체크 등 스프링 MVC 관련 처리
profile
🌱

0개의 댓글