17. Controller → DispatcherServlet: 응답 분기 시작
컨트롤러가 반환값을 만들고 나면, Spring MVC는 그것을 어떤 방식으로 응답할지 결정합니다.
오픈소스 기준으로는 ServletInvocableHandlerMethod.invokeAndHandle()가 반환값을 returnValueHandlers에 넘기고, 이후 DispatcherServlet.processDispatchResult()가 뷰 렌더링 여부를 판단합니다.
이번 단계의 역할
이 단계는 컨트롤러 반환값을 뷰 렌더링 흐름과 응답 본문(JSON 등) 작성 흐름으로 나누는 분기점입니다. 즉 웹 응답이 HTML 페이지인지 REST 응답인지 갈라지는 순간입니다.
호출 흐름 요약
- 컨트롤러 메서드가 반환값을 만듭니다.
ServletInvocableHandlerMethod.invokeAndHandle()가 반환값 처리기를 호출합니다.mavContainer상태에 따라 요청이 이미 처리됐는지 여부가 결정됩니다.DispatcherServlet.processDispatchResult()가 뷰 렌더링 여부를 확인합니다.- 이후 View 경로 또는 Response Body 경로로 나뉩니다.
호출 흐름 다이어그램
sequenceDiagram
participant Controller
participant SIHM as ServletInvocableHandlerMethod
participant Handlers as HandlerMethodReturnValueHandler
participant DS as DispatcherServlet
Controller-->>SIHM: returnValue
SIHM->>Handlers: handleReturnValue(...)
Handlers-->>DS: ModelAndView or requestHandled=true
alt View response
DS->>DS: render(mv, request, response)
else Body response
DS->>DS: no view rendering
end
핵심 코드
// ServletInvocableHandlerMethod.java
mavContainer.setRequestHandled(false);
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
// DispatcherServlet.java
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
else {
logger.trace("No view rendering, null ModelAndView returned.");
}
코드 해설
컨트롤러가 무엇을 반환했는지는 중요하지만, 더 중요한 것은 그 반환값을 어떤 HandlerMethodReturnValueHandler가 처리하느냐입니다.
ModelAndView라면 뷰 렌더링으로, @ResponseBody 계열이면 응답 본문 작성으로 이어집니다.
설계 의도
컨트롤러 반환 타입을 하나의 방식으로 고정하지 않고, 여러 응답 전략을 플러그인처럼 처리하기 위한 구조입니다. 이 덕분에 같은 MVC 파이프라인 안에서 템플릿 렌더링과 REST 응답을 모두 지원할 수 있습니다.
다음 단계 연결
뷰 렌더링 경로는 17-V1부터, JSON 응답 경로는 17-R1부터 이어집니다.
← 이전: 16. Service → Controller: 결과 반환 | 다음: 17-V1. Controller → DispatcherServlet: ModelAndView 반환