전체 목록
SpringMedium#070

Spring MVC의 요청 처리 흐름(DispatcherServlet 동작 방식)을 설명해주세요.

#Spring#MVC#DispatcherServlet#

답변 포인트

DispatcherServlet → HandlerMapping → HandlerAdapter → Controller → ViewResolver 순서입니다.

정답 및 해설

빠른 요약

1) 클라이언트 요청이 DispatcherServlet(Front Controller)에 도착 2) HandlerMapping으로 적절한 Controller(Handler) 탐색 3) HandlerAdapter로 해당 핸들러 실행 4) Controller가 비즈니스 로직 처리 후 ModelAndView 반환 5) ViewResolver가 논리 뷰 이름을 실제 View로 변환 6) View가 Model 데이터를 사용해 응답 렌더링 7) 응답 반환 @RestController의 경우: @ResponseBody로 인해 ViewResolver 대신 HttpMessageConverter가 JSON/XML으로 직렬화하여 응답.

Spring MVC는 Front Controller 패턴을 기반으로 동작합니다. 모든 HTTP 요청이 하나의 진입점인 DispatcherServlet을 통해 처리되며, 이후 각 역할에 특화된 컴포넌트들이 협력하여 응답을 생성합니다.

전체 요청 처리 흐름

Java

    
    
DispatcherServlet (Front Controller)
    
     1. HandlerMapping   Handler(Controller) 
    
     2. HandlerAdapter  Handler 
    
     3. Controller      ModelAndView 
    
     4. ViewResolver       View 
    
     5. View     

단계별 상세 설명

1단계: 클라이언트 요청 수신

클라이언트의 HTTP 요청이 서블릿 컨테이너(Tomcat)를 거쳐 DispatcherServlet에 도달합니다. web.xml 또는 Spring Boot의 자동 설정으로 모든 요청(/)이 DispatcherServlet에 매핑됩니다.

Java
// Spring Boot에서는 자동으로 설정됨
// 직접 설정이 필요한 경우:
@Bean
public ServletRegistrationBean<DispatcherServlet> dispatcherServlet() {
    DispatcherServlet servlet = new DispatcherServlet(applicationContext);
    return new ServletRegistrationBean<>(servlet, "/");
}

2단계: HandlerMapping으로 Handler 탐색

DispatcherServlet이 요청 URL과 HTTP 메서드에 맞는 핸들러(Controller)를 HandlerMapping에 질의합니다.

Java
// 내부적으로 이런 과정이 일어납니다:
// GET /users/1 → UserController.getUser(Long id) 메서드 탐색

@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping("/{id}")
    public UserResponse getUser(@PathVariable Long id) {
        // HandlerMapping이 이 메서드를 찾아냄
        return userService.findById(id);
    }
}

Spring MVC에는 여러 HandlerMapping 구현체가 있으며, RequestMappingHandlerMapping이 가장 일반적으로 사용됩니다.

3단계: HandlerAdapter로 Handler 실행

핸들러의 타입에 따라 적절한 HandlerAdapter가 선택되어 실제 메서드를 호출합니다. HandlerAdapter는 다양한 형태의 핸들러(Controller, HttpRequestHandler 등)를 일관된 방식으로 실행할 수 있게 해줍니다.

Java
// RequestMappingHandlerAdapter가 아래와 같은 작업을 처리합니다:
// 1. @RequestParam, @PathVariable, @RequestBody 등 파라미터 바인딩
// 2. 메서드 실행
// 3. 반환값 처리 (ModelAndView, String, ResponseEntity 등)

4단계: Controller 비즈니스 로직 처리

Controller는 Service를 호출해 비즈니스 로직을 수행하고 결과를 반환합니다.

Java
@Controller  // @RestController가 아닌 경우
@RequestMapping("/orders")
public class OrderController {

    private final OrderService orderService;

    @GetMapping("/{id}")
    public String getOrder(@PathVariable Long id, Model model) {
        Order order = orderService.findById(id);
        model.addAttribute("order", order);
        return "order/detail";  // 논리 뷰 이름 반환
    }
}

5단계: ViewResolver로 View 결정

Controller가 반환한 논리 뷰 이름(예: "order/detail")을 실제 View 객체로 변환합니다.

Java
// application.yml 설정
// spring:
//   mvc:
//     view:
//       prefix: /WEB-INF/views/
//       suffix: .jsp

// "order/detail" → /WEB-INF/views/order/detail.jsp
ViewResolver 종류설명
InternalResourceViewResolverJSP 파일로 변환
ThymeleafViewResolverThymeleaf 템플릿으로 변환
BeanNameViewResolver빈 이름으로 View 탐색

6단계: View 렌더링 및 응답 반환

View가 Model 데이터를 사용해 HTML 등의 응답을 생성하고 클라이언트에 반환합니다.

@RestController의 경우: HttpMessageConverter

@RestController(또는 @ResponseBody)를 사용하면 ViewResolver 대신 HttpMessageConverter가 반환값을 직렬화합니다.

Java

    
    
DispatcherServlet
    
     HandlerMapping  Controller 
     HandlerAdapter  Controller 
    
     @ResponseBody 
           
           
    HttpMessageConverter (Jackson )
            Java   JSON/XML 
           
    HTTP Response Body
Java
@RestController  // @Controller + @ResponseBody
@RequestMapping("/api/users")
public class UserApiController {

    @GetMapping("/{id}")
    public UserResponse getUser(@PathVariable Long id) {
        // UserResponse 객체가 Jackson에 의해 JSON으로 직렬화됨
        return userService.findById(id);
    }

    @PostMapping
    public ResponseEntity<UserResponse> createUser(@RequestBody CreateUserRequest request) {
        UserResponse response = userService.create(request);
        return ResponseEntity
            .status(HttpStatus.CREATED)
            .body(response);
    }
}

주요 HttpMessageConverter 구현체:

Converter처리 타입
MappingJackson2HttpMessageConverterJSON (application/json)
StringHttpMessageConverter문자열 (text/plain)
ByteArrayHttpMessageConverter바이트 배열 (application/octet-stream)
MarshallingHttpMessageConverterXML (application/xml)

HandlerInterceptor와의 관계

HandlerInterceptor는 DispatcherServlet 이후, Controller 실행 전후에 동작합니다.

Java
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        // Controller 실행 전 — false 반환 시 요청 중단
        String token = request.getHeader("Authorization");
        if (!tokenService.isValid(token)) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        // Controller 실행 후, View 렌더링 전
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        // View 렌더링 후 (예외 발생 여부 무관)
        // 리소스 정리에 사용
    }
}

전체 컴포넌트 역할 요약

컴포넌트역할
DispatcherServlet요청을 받아 전체 흐름을 조율하는 Front Controller
HandlerMappingURL과 HTTP 메서드로 적절한 Handler 탐색
HandlerAdapter다양한 형태의 Handler를 일관되게 실행
Controller실제 비즈니스 로직 처리 및 결과 반환
ViewResolver논리 뷰 이름을 실제 View로 변환
ViewModel 데이터를 사용해 최종 응답 생성
HttpMessageConverter@ResponseBody 사용 시 객체를 JSON/XML로 직렬화

관련 질문

같은 카테고리/태그 기준