Spring MVC 구조와 요청 처리 흐름

한눈에 보기

Spring MVC는 프론트 컨트롤러 패턴 기반으로 모든 요청이 디스패처 서블릿을 거친다. 핸들러 매핑과 어댑터, HttpMessageConverter를 통한 요청 처리 흐름과 필터, 인터셉터 차이를 설명한다.

최종 업데이트 2026.09.17

Spring MVC는 프론트 컨트롤러(Front Controller) 패턴을 기반으로 HTTP 요청을 처리하는 스프링 프레임워크의 웹 계층 모듈이다. 모든 요청은 디스패처 서블릿(DispatcherServlet)이라는 단일 진입점으로 들어오고, 디스패처 서블릿이 핸들러 매핑(Handler Mapping), 핸들러 어댑터(Handler Adapter), 뷰 리졸버(View Resolver) 같은 구성요소에 일을 위임하는 구조로 동작한다. Spring Boot 3.x에서는 이 구성이 자동으로 등록되어 개발자는 컨트롤러 작성에만 집중할 수 있다.

프론트 컨트롤러 패턴과 DispatcherServlet

프론트 컨트롤러 패턴은 요청마다 서블릿을 따로 만들지 않고, 하나의 컨트롤러가 모든 요청을 받아 공통 처리를 한 뒤 세부 처리를 위임하는 패턴이다. Spring MVC에서 이 역할을 맡는 것이 디스패처 서블릿이다. 인코딩, 예외 처리, 뷰 렌더링 위임 같은 공통 관심사를 한곳에서 처리하므로 개별 컨트롤러는 비즈니스 요청 처리에만 집중한다. 스프링 부트는 디스패처 서블릿을 자동 구성으로 등록하고 기본적으로 모든 경로에 매핑한다. 디스패처 서블릿은 특정 컨트롤러 방식에 의존하지 않고 HandlerMapping, HandlerAdapter 같은 인터페이스에만 의존하기 때문에, 애너테이션(Annotation) 기반 컨트롤러든 함수형 엔드포인트든 같은 흐름으로 처리할 수 있다.

요청 처리 흐름

클라이언트 요청이 응답으로 돌아가기까지의 흐름은 다음과 같다.

  1. 클라이언트의 요청이 서블릿 컨테이너의 필터(Filter)를 거쳐 디스패처 서블릿에 도착한다.
  2. 디스패처 서블릿이 HandlerMapping에 물어 요청 URL과 메서드에 맞는 핸들러(컨트롤러 메서드)를 찾는다. @RequestMapping 기반이라면 RequestMappingHandlerMapping이 담당한다.
  3. 찾은 핸들러를 실행할 수 있는 HandlerAdapter를 조회한다. 애너테이션 컨트롤러는 RequestMappingHandlerAdapter가 처리한다.
  4. 핸들러 실행 전에 등록된 인터셉터(Interceptor)의 preHandle이 호출된다.
  5. 핸들러 어댑터가 ArgumentResolver로 @PathVariable, @RequestBody 같은 파라미터를 만들어 컨트롤러 메서드를 호출한다.
  6. 반환 값을 ReturnValueHandler가 해석한다. 뷰 이름이면 ModelAndView로, @ResponseBody면 HttpMessageConverter로 바로 응답 본문을 쓴다.
  7. 뷰 렌더링이 필요한 경우 ViewResolver가 뷰 이름을 실제 View 객체로 바꾸고, 모델 데이터를 넣어 렌더링한다.
  8. 인터셉터의 postHandle과 afterCompletion이 호출되고 응답이 클라이언트로 돌아간다. 처리 중 예외가 나면 HandlerExceptionResolver가 개입하며, @RestControllerAdvice의 @ExceptionHandler가 이 지점에서 동작한다.

REST 응답과 HttpMessageConverter

REST API에서는 뷰 렌더링 대신 객체를 JSON으로 직렬화해 응답 본문에 쓴다. 이를 담당하는 것이 HttpMessageConverter이며, 요청의 Content-Type과 응답의 Accept 헤더를 보고 적절한 컨버터를 고른다. JSON에는 잭슨(Jackson) 기반 컨버터가 기본으로 쓰인다.

@RestController
@RequestMapping("/api/members")
public class MemberController {

    private final MemberService memberService;

    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @GetMapping("/{id}")
    public MemberResponse find(@PathVariable Long id) {
        return memberService.findById(id);
    }

    @PostMapping
    public ResponseEntity<MemberResponse> create(@RequestBody @Valid MemberCreateRequest request) {
        MemberResponse response = memberService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
}

@RestController는 @Controller에 @ResponseBody를 합친 애너테이션으로, 모든 메서드의 반환 값이 뷰 이름이 아니라 응답 본문으로 처리된다. @RequestBody 파라미터는 요청 본문을 컨버터가 객체로 역직렬화한 결과다.

필터와 인터셉터 비교

공통 처리를 어디에 둘지 결정할 때 필터와 인터셉터의 차이를 알아야 한다.

구분필터인터셉터
소속서블릿 컨테이너 표준Spring MVC
실행 위치디스패처 서블릿 도달 이전핸들러 실행 전후
접근 정보ServletRequest, ServletResponse선택된 핸들러 정보까지 접근 가능
예외 처리@ExceptionHandler 적용 밖스프링 예외 처리 흐름 안
대표 용도인코딩, CORS, 보안(Spring Security 필터 체인)인증 확인, 로깅, 권한 검사

디스패처 서블릿보다 앞 단계에서 요청 전체를 다뤄야 하면 필터, 스프링 컨텍스트의 빈(Bean)과 핸들러 정보를 활용해야 하면 인터셉터가 적합하다. 컨트롤러 메서드 호출을 세밀하게 가로채야 한다면 AOP(Aspect Oriented Programming)도 선택지가 된다.

면접에서 이렇게 물어본다

  • 디스패처 서블릿이 요청을 받아 응답을 반환하기까지의 흐름을 구성요소 이름과 함께 설명해 보라.
  • 프론트 컨트롤러 패턴을 사용해서 얻는 이점이 무엇인지 말해 보라.
  • HandlerMapping과 HandlerAdapter를 인터페이스로 분리한 이유를 설명해 보라.
  • @RestController의 반환 값이 JSON으로 변환되는 과정을 HttpMessageConverter와 연결해 설명해 보라.
  • 필터와 인터셉터의 차이, 그리고 각각 어떤 상황에 쓰는지 예를 들어 말해 보라.
Spring / JPA 문서 전체 보기

이 개념, 내 코드에서는 어떻게 물어볼까요

데브핏(DevFit)에 채용공고 URL을 붙여 넣고 레포지토리를 연결하면, 내가 쓴 커밋에서 예상 질문과 어필 포인트를 만듭니다. 하루 10회까지 무료입니다. 합불 판정이나 지원자 랭킹은 만들지 않고, 최종 판단은 사람이 합니다.

공고 넣고 시작하기