Deep Dive /Java Web /11

11. DispatcherServlet → HandlerInterceptor: preHandle()

DispatcherServlet은 HandlerExecutionChain을 받은 뒤 가장 먼저 preHandle()을 실행합니다. 이 단계는 컨트롤러 진입 전에 요청을 통과시킬지, 여기서 중단할지를 결정하는 관문입니다.


이번 단계의 역할

컨트롤러 실행 전 공통 검사와 차단 로직을 수행하는 단계입니다.


호출 흐름 요약

  1. DispatcherServlet이 getHandler(...) 결과를 받습니다.
  2. mappedHandler.applyPreHandle(...)를 호출합니다.
  3. 각 인터셉터의 preHandle()이 정방향으로 실행됩니다.
  4. 하나라도 false를 반환하면 컨트롤러 호출이 중단됩니다.
  5. 이미 실행된 인터셉터는 afterCompletion()으로 정리됩니다.

호출 흐름 다이어그램

sequenceDiagram participant DS as DispatcherServlet participant Chain as HandlerExecutionChain participant I1 as Interceptor 1 participant I2 as Interceptor 2 participant Controller DS->>Chain: applyPreHandle(request, response) Chain->>I1: preHandle(...) I1-->>Chain: true Chain->>I2: preHandle(...) alt false 반환 I2-->>Chain: false Chain->>Chain: triggerAfterCompletion() Chain-->>DS: false else true 반환 I2-->>Chain: true Chain-->>DS: true DS->>Controller: continue end

핵심 코드

// DispatcherServlet.java
mappedHandler = getHandler(processedRequest);
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
}
// HandlerExecutionChain.java
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    for (int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
        }
        this.interceptorIndex = i;
    }
    return true;
}

코드 해설

핵심은 false를 반환해도 이미 실행된 인터셉터 정리는 반드시 이뤄진다는 점입니다. 그래서 Spring은 interceptorIndex를 기록해, 성공적으로 진입한 인터셉터까지만 afterCompletion()을 역순으로 호출합니다.


설계 의도

1) 컨트롤러 전 차단 지점을 제공하기 위해

인증, 권한 검사, 요청 차단 같은 공통 로직은 컨트롤러 전에 끝내는 편이 안정적입니다.

2) 요청 중단 시에도 정리 로직을 안전하게 실행하기 위해

중간 실패가 나더라도 이미 통과한 인터셉터의 자원 정리를 보장하려면, 별도의 완료 처리 구조가 필요합니다.


다음 단계 연결

다음 문서 12번에서는 preHandle()을 통과한 뒤, Spring이 컨트롤러 파라미터를 만들기 위해 HandlerMethodArgumentResolver를 호출하는 과정을 봅니다.

← 이전: 10. HandlerMapping → DispatcherServlet | 다음: 12. DispatcherServlet → HandlerMethodArgumentResolver