4. Spring MVC 요청 처리 흐름

HTTP 요청이 들어와서 @RestController의 메서드가 실행되기까지 수많은 컴포넌트를 거칩니다. Filter, DispatcherServlet, Interceptor, AOP가 각각 어느 시점에 무슨 역할을 하는지 알아야 인증·로깅·트랜잭션 처리를 올바른 위치에 구현할 수 있습니다.

1. HTTP 요청 처리 전체 흐름

HTTP Request → Response 전체 경로
① Filter (서블릿 컨테이너)
Tomcat 레벨. Spring 컨텍스트 밖. 가장 먼저 실행.
↓ (체인 진입)
② DispatcherServlet
Spring MVC의 Front Controller. 모든 요청의 진입점.
↓ HandlerMapping으로 Controller 탐색
③ HandlerInterceptor.preHandle
Spring 레벨. HttpServletRequest/Response 접근 가능.
↓ HandlerAdapter → 파라미터 바인딩
④ AOP Advice (Before)
Spring Bean 메서드 실행 직전. @Transactional 시작.
⑤ Controller 메서드 실행
@GetMapping, @PostMapping 등 핸들러 메서드.
↑ 리턴값 → MessageConverter → JSON 직렬화
⑥ AOP Advice (After/AfterReturning)
@Transactional 커밋/롤백.
⑦ HandlerInterceptor.postHandle / afterCompletion
ModelAndView 수정(postHandle), 리소스 정리(afterCompletion).
⑧ Filter (체인 복귀)
Response 후처리. CORS 헤더 추가, 응답 압축 등.

2. DispatcherServlet — Spring MVC의 중심

DispatcherServlet은 Front Controller 패턴의 구현체입니다. 모든 HTTP 요청을 하나의 서블릿이 받아서 적절한 핸들러(Controller)에게 위임합니다.

DispatcherServlet 내부 처리 단계
// 1. HandlerMapping으로 Handler 탐색
//    @RequestMapping URL 패턴 → Controller 메서드
HandlerExecutionChain handler =
    handlerMapping.getHandler(request);

// 2. HandlerAdapter 선택
//    메서드 시그니처에 맞는 어댑터 선택
//    파라미터 바인딩, 리턴값 처리 담당
HandlerAdapter adapter =
    getHandlerAdapter(handler.getHandler());

// 3. 핸들러 실행
ModelAndView mv =
    adapter.handle(request, response, handler);

// 4. ViewResolver (REST API는 건너뜀)
//    @ResponseBody → MessageConverter로 직렬화
//    → JSON/XML 응답 바디 작성
@Controller vs @RestController
// @Controller: View 이름 반환
@Controller
public class PageController {
    @GetMapping("/home")
    public String home(Model model) {
        model.addAttribute("msg", "hello");
        return "home"; // ViewResolver → home.html
    }
}

// @RestController: 객체를 Body로 직렬화
// @Controller + @ResponseBody 합성
@RestController
public class ApiController {
    @GetMapping("/api/user")
    public UserDto getUser() {
        return new UserDto("kim"); // → JSON
        // MessageConverter(Jackson)이 직렬화
    }
}

3. Filter vs Interceptor vs AOP 비교

구분실행 위치접근 가능한 것주요 용도
Filter 서블릿 컨테이너 (Tomcat)
Spring 컨텍스트 밖
HttpServletRequest/Response
ServletContext
(Spring Bean 주입 가능하지만 주의)
인코딩 설정
CORS 헤더 처리
보안 (Spring Security는 Filter 기반)
요청/응답 로깅
응답 압축
Interceptor DispatcherServlet 이후
Spring 컨텍스트 내
HttpServletRequest/Response
Handler(Controller 메서드 정보)
Spring Bean 자유롭게 사용
인증/인가 체크
로그인 여부 확인
요청 처리 시간 측정
공통 모델 데이터 주입
AOP Spring Bean 메서드 실행 시점
(프록시 레이어)
메서드 파라미터, 리턴값, 예외
JoinPoint 정보
HTTP 정보 없음
트랜잭션 (@Transactional)
성능 측정 (메서드 단위)
캐싱 (@Cacheable)
감사 로그 (비즈니스 메서드)
Filter 구현 예시 — CORS
@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(
            ServletRequest req,
            ServletResponse res,
            FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse response =
            (HttpServletResponse) res;
        response.setHeader(
            "Access-Control-Allow-Origin", "*");
        response.setHeader(
            "Access-Control-Allow-Methods",
            "GET, POST, PUT, DELETE");

        chain.doFilter(req, res); // 다음 필터로
    }
}
Interceptor 구현 예시 — 인증
@Component
public class AuthInterceptor
        implements HandlerInterceptor {

    @Override
    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) {

        String token = request.getHeader("Authorization");
        if (!tokenService.validate(token)) {
            response.setStatus(401);
            return false; // Controller 실행 중단
        }
        return true; // 계속 진행
    }

    @Override
    public void afterCompletion(..., Exception ex) {
        // 요청 처리 완료 후 항상 실행
        // 예외 발생해도 실행됨 (리소스 정리)
    }
}

4. 면접 대비 핵심 Q&A

Q1. "Filter와 Interceptor의 가장 큰 차이는?"

실행 위치가 다릅니다. Filter는 서블릿 컨테이너(Tomcat) 레벨에서 동작합니다 — Spring ApplicationContext 바깥입니다. 모든 서블릿 요청을 가로챌 수 있고, Spring Security가 이 레이어를 사용합니다. Interceptor는 DispatcherServlet 이후 Spring 컨텍스트 내부에서 동작합니다. Handler(어떤 Controller 메서드가 처리할지) 정보를 알 수 있고, Spring Bean을 자유롭게 주입해 쓸 수 있습니다. 정적 리소스(css, js)는 DispatcherServlet에서 처리되지 않는 경우 Interceptor를 통과하지 않을 수 있지만, Filter는 항상 통과합니다.

Q2. "AOP를 Interceptor 대신 쓰는 경우는?"

Interceptor는 HTTP 요청 단위로만 동작합니다. AOP는 HTTP와 관계없이 임의의 Spring Bean 메서드에 적용할 수 있습니다. 예를 들어 배치 서비스, 스케줄러, 이벤트 리스너 메서드에 트랜잭션이나 성능 측정을 적용할 때는 Interceptor로 할 수 없고 AOP를 써야 합니다. 또한 메서드 파라미터나 리턴값에 접근해야 할 때도 AOP의 @Around가 유리합니다.

Q3. "DispatcherServlet이 Front Controller 패턴을 쓰는 이유는?"

Front Controller가 없으면 각 서블릿이 공통 처리(인증, 로깅, 예외 처리)를 중복으로 구현해야 합니다. DispatcherServlet이 모든 요청의 단일 진입점 역할을 하면서 공통 처리는 한 곳에서, 실제 비즈니스는 각 Controller에서 담당하는 구조가 됩니다. 확장도 용이합니다 — 새 Controller를 추가할 때 Servlet 등록 없이 @RequestMapping만 선언하면 됩니다.

이 챕터의 핵심 한 줄

Filter(서블릿 컨테이너) → DispatcherServlet → Interceptor → AOP → Controller 순서로 요청이 흐르며, 인증/CORS는 Filter, 로그인 체크는 Interceptor, 트랜잭션/캐싱은 AOP가 담당한다.