자바 백엔드 입문 25편 — DispatcherServlet 요청 처리 흐름

2026-05-16자바 백엔드 입문

자바 백엔드 입문 25편. Phase 4 Web MVC 시작. 브라우저의 GET 요청이 Spring 컨트롤러까지 도달하는 9단계 흐름과 DispatcherServlet의 역할을 호텔 프런트 데스크 비유로 풀어쓴 학습 노트.

📚 자바 백엔드 입문 · 25편 — DispatcherServlet 요청 처리 흐름

이 글은 자바 백엔드 입문 시리즈 59편 중 25편이에요. Phase 3 SpEL·AOP 3편이 끝났고, 이번 25편부터 Phase 4 Web MVC 5편으로 들어갑니다. 가장 먼저 — "브라우저가 보낸 HTTP 요청이 Spring 컨트롤러까지 어떻게 도달하는가" 의 전체 흐름을 풀어요. 중심에 있는 DispatcherServlet 이 이번 글의 주인공.

DispatcherServlet이 헷갈리는 이유

처음 Spring 코드를 보면 — @RestController 박힌 메서드가 어떻게 알아서 호출되는지가 마법처럼 느껴져요. "Tomcat이 받아서 뭐가 어떻게 거치고 우리 메서드까지 오는가" 의 흐름이 안 잡혀요.

이 글에서는 호텔 프런트 데스크 비유로 풀어요. 호텔 손님(HTTP 요청)이 도착하면 프런트 데스크(DispatcherServlet) 한 직원이 "어느 방인지 확인 → 담당 객실 매니저(컨트롤러) 호출 → 요청 처리 → 응답" 의 전체 흐름을 조정하는 그림. 끝까지 따라오시면 9단계 요청 처리 흐름이 한 번에 들어와요.

DispatcherServlet — 모든 요청의 정문

DispatcherServlet"모든 HTTP 요청의 단일 진입점" 이에요. Spring Web MVC의 핵심 부품이고, Tomcat이 받은 요청을 가장 먼저 받는 자바 객체.

비유 — 호텔에 도착한 손님은 무조건 프런트 데스크부터 거쳐요. "몇 호실이세요? 키 받으세요? 무엇이 필요하세요?" — 프런트가 모든 질문을 받고, 적절한 부서로 안내해줍니다. DispatcherServlet도 똑같아요. 브라우저가 GET /orders/123 보내든 POST /payments 보내든 — 모든 요청이 일단 DispatcherServlet을 통과해요.

┌──────────┐   HTTP    ┌────────────────────┐    ┌──────────────┐
│ 브라우저   │ ───────→  │ DispatcherServlet  │ →  │ 적절한 컨트롤러 │
│ (손님)    │           │ (프런트 데스크)      │    │ (객실 매니저)   │
└──────────┘   응답 ←   └────────────────────┘ ←  └──────────────┘

Spring Boot는 시작할 때 DispatcherServlet을 자동으로 생성하고 / 경로 전체에 매핑해줘요. 우리가 직접 박을 일 X.

요청 처리 9단계 — 그림으로 보기

브라우저가 GET /orders/123 보냈을 때 흐름.

[1] 브라우저  ──→  Tomcat (HTTP 서버, 8080 포트)
[2] Tomcat   ──→  DispatcherServlet (Spring 진입점)
[3] DispatcherServlet ──→ HandlerMapping  ("어느 컨트롤러?")
[4] HandlerMapping ──→ HandlerAdapter      ("어떻게 호출?")
[5] HandlerAdapter ──→ 컨트롤러 메서드     (실제 비즈니스 로직)
[6] 컨트롤러 ←── HandlerAdapter            (반환값 수신)
[7] HandlerAdapter ──→ MessageConverter    (반환값 → JSON·HTML 변환)
[8] DispatcherServlet ──→ Tomcat           (응답 본문 + 상태 코드)
[9] Tomcat   ──→  브라우저                  (HTTP 응답)

이 9단계가 매 요청마다 일어나요. 우리가 직접 신경 쓰는 건 5번 — 컨트롤러 메서드 — 만. 나머지 8단계는 Spring이 다 자동 처리.

5대 핵심 부품 — Spring MVC의 다섯 직원

DispatcherServlet 한 명이 모든 일을 다 하는 게 아니에요. 보조 부품 5개가 같이 일해요.

부품 역할 비유
DispatcherServlet 요청 진입점, 전체 흐름 조정 호텔 프런트 데스크 매니저
HandlerMapping URL → 컨트롤러 매핑 객실 배정표 ("이 손님은 305호")
HandlerAdapter 컨트롤러 메서드 호출 방식 결정 객실 매니저 호출 매뉴얼
HandlerInterceptor 요청 전/후 가로채기 로비 보안 직원
HttpMessageConverter 자바 객체 ↔ JSON/XML 변환 통역사
ViewResolver 뷰 이름 → 실제 HTML 템플릿 객실 인테리어 카탈로그

이 6명이 매 요청마다 협업해요. 우리가 @RestController + @GetMapping("/orders/{id}") 한 메서드 박으면 — Spring 시작 시 HandlerMapping이 "/orders/{id} 요청은 이 메서드로 보내" 라는 매핑을 자동 등록.

HandlerMapping — URL을 컨트롤러로 연결

HandlerMapping 의 일은 한 줄. "이 URL 요청을 처리할 컨트롤러 메서드를 찾아라".

Spring Boot가 시작될 때 컴포넌트 스캔으로 발견한 모든 @Controller·@RestController 클래스의 @RequestMapping·@GetMapping·@PostMapping 어노테이션을 읽어 — "GET /orders/{id}OrderController.getOrder()" 같은 매핑 테이블을 한 번에 만들어둬요. 요청이 들어오면 이 테이블에서 즉시 조회해 매칭되는 메서드를 반환.

@RestController
public class OrderController {

    @GetMapping("/orders/{id}")           // ← HandlerMapping이 이 메서드를 발견·등록
    public Order getOrder(@PathVariable Long id) {
        return orderService.findById(id);
    }

    @PostMapping("/orders")               // ← 또 다른 매핑
    public Order createOrder(@RequestBody OrderRequest req) {
        return orderService.create(req);
    }
}

같은 OrderController 안에 메서드가 여러 개 있어도 — HandlerMapping이 "메서드 종류 + URL 경로" 조합으로 각각 따로 등록.

HandlerAdapter — 메서드 매개변수 자동 채우기

HandlerMapping이 "이 메서드를 호출해라" 정보를 주면, HandlerAdapter 가 실제 호출을 담당해요. 핵심 역할 — 메서드 매개변수를 HTTP 요청에서 자동으로 추출해 채우기.

@GetMapping("/orders/{id}")
public Order getOrder(
    @PathVariable Long id,                // URL 경로에서 추출
    @RequestParam(required = false) String filter,   // 쿼리 스트링에서
    @RequestHeader("Authorization") String token,    // HTTP 헤더에서
    HttpServletRequest request) {                    // 전체 요청 객체
    return orderService.findById(id);
}

이 한 메서드를 호출하려면 4가지 정보가 필요한데 — @PathVariable·@RequestParam·@RequestHeader 어노테이션을 보고 HandlerAdapter가 알아서 HTTP 요청에서 추출해 메서드 매개변수에 끼워줘요. 22편에서 깊이 다룰 부분.

HttpMessageConverter — JSON 자동 변환

컨트롤러가 자바 객체를 반환하면 — Order 객체를 어떻게 JSON으로 변환해 브라우저에 보낼까? HttpMessageConverter 가 이 변환을 자동 처리해요.

@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable Long id) {
    return orderService.findById(id);   // Order 객체 반환
}
// ↑ 이 반환값을 Jackson(기본 컨버터)이 JSON으로 자동 변환
// → 브라우저로 보내는 응답 본문: {"id": 123, "amount": 10000, ...}

기본 컨버터는 Jackson. Spring Boot가 jackson-databind 의존성 자동 포함이라 별도 설정 없이 JSON 변환이 동작해요. XML 응답이 필요하면 Jackson XML 추가, ProtoBuf 필요하면 그 컨버터 추가 — 패턴은 동일.

HandlerInterceptor — 요청 전/후 가로채기

매 요청이 컨트롤러에 닿기 전/후 공통 작업을 하고 싶으면 — HandlerInterceptor 를 박아요. AOP와 비슷하지만 "HTTP 요청 레벨" 에서만 동작.

@Component
public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        log.info("→ {} {}", req.getMethod(), req.getRequestURI());
        return true;   // false 반환 시 컨트롤러 호출 X
    }

    @Override
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
        log.info("← {} {}", res.getStatus(), req.getRequestURI());
    }
}

자주 쓰이는 시나리오 — 인증 검증·로깅·요청 카운팅. AOP보다 가볍고 HTTP 컨텍스트(헤더·경로 등) 접근이 자연스러워요.

DispatcherServlet과 ViewResolver — 전통 MVC 패턴

REST API가 아니라 "HTML 페이지를 렌더해서 응답" 하는 옛 패턴에서는 ViewResolver 가 등장해요.

@Controller
public class HomeController {

    @GetMapping("/")
    public String home(Model model) {
        model.addAttribute("message", "Hello");
        return "home";   // 뷰 이름 반환 (HTML 파일명 아님)
    }
}

컨트롤러가 "home" 이라는 문자열을 반환하면 — ViewResolver가 "home 이라는 이름의 템플릿 파일을 찾아" 처리. 보통 src/main/resources/templates/home.html (Thymeleaf 기본).

현대 백엔드는 거의 다 REST API 패턴(JSON 응답)이라 ViewResolver를 직접 만질 일이 드물어요. 다만 "이런 경로도 있다" 는 알아둘 가치 있어요.

💡 @RestController vs @Controller 한 줄 차이

@Controller = ViewResolver 거쳐 HTML 렌더 (전통 MVC). @RestController = @Controller + @ResponseBody, MessageConverter로 JSON 직접 반환. 현대 백엔드는 거의 다 @RestController.

한 줄 정리 — DispatcherServlet은 모든 HTTP 요청의 진입점. HandlerMapping·HandlerAdapter·MessageConverter·HandlerInterceptor·ViewResolver 5명의 보조 부품이 9단계 흐름으로 협업. 우리는 컨트롤러 메서드만 짜면 됨.

시험 직전 한 번 더 — DispatcherServlet 입문자가 매번 헷갈리는 것

  • DispatcherServlet = 모든 HTTP 요청의 단일 진입점
  • "프런트 컨트롤러 패턴(Front Controller Pattern)" 의 자바 구현
  • Tomcat이 요청 받으면 → DispatcherServlet에 전달
  • DispatcherServlet은 자바 표준 HttpServlet 의 서브클래스
  • Spring Boot 시작 시 자동 생성 + / 매핑 — 우리가 박을 일 X
  • 9단계 흐름 = Tomcat → DispatcherServlet → HandlerMapping → HandlerAdapter → 컨트롤러 → MessageConverter → 응답
  • HandlerMapping = URL을 컨트롤러 메서드로 매핑
  • HandlerAdapter = 메서드 매개변수 자동 채우기
  • HttpMessageConverter = 자바 객체 ↔ JSON/XML 변환
  • HandlerInterceptor = 요청 전/후 가로채기 (AOP보다 HTTP 컨텍스트 친화적)
  • ViewResolver = 뷰 이름 → HTML 템플릿 파일 매핑
  • 기본 MessageConverter = Jackson (JSON)
  • @Controller = HTML 렌더 (ViewResolver), @RestController = JSON 직접 반환
  • HandlerInterceptor preHandle 에서 false 반환 시 컨트롤러 호출 차단
  • preHandle / postHandle / afterCompletion 3단계 콜백
  • @RestController 의 반환값은 무조건 응답 본문 (뷰 이름 X)
  • 같은 URL에 여러 컨트롤러 메서드 매핑 충돌 시 시작 실패
  • HandlerMapping은 시작 시 한 번 매핑 테이블 만들어 캐싱
  • DispatcherServlet 안에 자동 등록되는 Bean들은 Spring Boot가 자동 설정
  • 트래픽 9단계 = 모든 요청 통과. "Spring MVC의 심장"

시리즈 다른 편 (앞뒤 글 모음)

이전 글:

다음 글:

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!