목차
RequestMappingHandlerAdapter의 요청 및 응답 처리 전체 구조
https://kimyongjun0129.tistory.com/185
[Spring] Spring MVC, RequestMappingHandlerAdapter의 요청 및 응답 처리 과정
목차RequestMappingHandlerAdapter 구조용어 정리전체 흐름 요약 RequestMappingHandlerAdapter 구조 용어 정리DispatcherServlet : Spring MVC의 핵심 프론트 컨트롤러클라이언트의 모든 요청을 가로채고, 적적할 컨트롤
kimyongjun0129.tistory.com
RequestMappingHandlerAdapter 구조
- `RequestMappingHandlerAdapter`는 `ArgumentResolver`를 호출하여 Controller에 필요한 다양한 파라미터 값을 변환(바인딩)합니다.
- `ReturnValueHandler`의 결과는 `RequestMappingHandlerAdapter`를 통해 최종적으로 뷰 렌더링 또는 HTTP 응답으로 이어집니다.
ArugmentResolver
정의 :
컨트롤러 메서드의 파라미터를 객체로 변환(바인딩)해주는 컴포넌트입니다.
파라미터 종류 :
- @RequestParam
- @RequestBody
- @RequestParam
- HttpServletRequest, Model, HttpEntity
✨ 들어오는 Http 요청의 파라미터 타입이나 어노테이션 등에 에 따라 Resolver가 존재하면 호출됩니다.
ArgumentResolver 구현체 종류 :
파라미터 또는 어노테이션 | 해당 Resolver 클래스 | 설명 |
`@RequestParam` | RequestParamMethodArgumentResolver | 쿼리 파라미터, 폼 데이터 등을 처리합니다. @RequestParam("id") |
`@RequestBody` | RequestResponseBodyMethodProcessor | HTTP 요청의 Body(JSON, XML 등)를 객체로 변환 |
`@PathVariable` | PathVariableMethodArgumentResolver | URL 경로 변수에 바인딩된 값을 처리 |
`@ModelAttribute` | ModelAttributeMethodProcessor | 폼 바인딩 객체 (e.g. UserForm userForm) |
`HttpServletRequest` | ServletRequestMethodArgumentResolver | 서블릿 API 타입 (HttpServletRequest, HttpServletResponse) |
`HttpServletResponse` | ServletRequestMethodArgumentResolver | 위와 동일 |
`HttpSession` | ServletRequestMethodArgumentResolver | 위와 동일 |
`Model` | ModelMethodProcessor | 컨트롤러 메서드에서 Model 주입 |
`HttpEntity<T>` | HttpEntityMethodProcessor | HTTP 요청의 전체 내용을 추상화한 객체 |
`RequestEntity<T>` | HttpEntityMethodProcessor | HttpEntity + 요청 정보 (URL, Header 등 포함) |
- 각 어노테이션과 파라미터에 대한 resolver 클래스 들은 `HandlerMethodArgumentResolver` 인터페이스를 구현하고 있습니다.
@RequestBody는 HttpMessageConverter가 변환해주지 않나? @RequestBody의 Resolver는 왜 존재할까?
❗결론부터 말하자면, 실제 변환은 `HttpMessageConverter`가 담당하는 것이 맞습니다.
그러면 ` RequestResponseBodyMethodProcessor`의 역할은 무엇일까요?
실제 동작 순서
1. Spring은 컨트롤러 메서드 파라미터를 분석하고, `HandlerMethodArgumentResolver` 구현체들이 저장된 리스트를 순회하면서, `supportsParameter()`를 호출하여 검증합니다.
for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
return resolver.resolveArgument(...); // 여기서 파라미터 값을 만들어냄
}
}
2. `@RequestBody`에 대한 resolver가 맞는지 검증합니다.
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
- `MethodParameter parameter` 안에, 해당 컨트롤러 메서드의 파라미터 정보 전체가 들어있습니다.
- `RequestResponseBodyMethodProcessor`의 `supportsParameter()`가 `true`를 반환합니다.
3. 그 후 `RequestResponseBodyMethodProcessor`은 `resolveArgument()` 내부에서 다음 코드를 실행합니다.
@Override
public Object resolveArgument(...) {
...
return readWithMessageConverters(request, methodParam, paramType);
}
- 등록된 `HttpMessageConverter` 리스트를 순회합니다.
- `canRead(...)`로 해당 타입을 처리할 수 있는 Converter 찾습니다.
- 찾으면 `read(...)` 호출해서 Java 객체로 변환합니다.
결론
- @RequestBody 자체는 Resolver + Converter 협업으로 작동합니다.
- RequestResponseBodyMethodProcessor는 "연결자" 역할
- 어떤 파라미터에 @RequestBody가 붙어있는지 감지하고,
- 적절한 HttpMessageConverter를 선택해서 변환을 실행합니다.
- HttpMessageConverter는 "실제 파싱/직렬화 담당자"입니다.







✨위에서 처럼 각 어노테이션과 파라미터에 대한 resolver들은 `HandlerMethodArgumentResolver`를 구현하고 있습니다.
예시 :
@GetMapping("/user")
public String example(
@RequestParam("id") String id, // RequestParamMethodArgumentResolver
@RequestBody User user, // RequestResponseBodyMethodProcessor
HttpServletRequest request, // ServletRequestMethodArgumentResolver
Model model, // ModelMethodProcessor
HttpEntity<String> httpEntity // HttpEntityMethodProcessor
) {
...
}
HandlerMethodArgumentResolver
- `ArgumentResolver`의 실제 이름
- resolver 클래스들은 이 인터페이스를 구현한 형태입니다.
- 이 인터페이스를 구현하여, 커스텀하게 파라미터를 만들 수 있습니다. (확장)
- `supportsParameter(MethodParameter parameter);`
- 컨트롤러가 필요로하는 메서드의 파라미터를 지원하는지 여부를 검사합니다.
- 지원한다면 `resolveArgument()` 메서드를 통해 Object(객체)로 만들어줍니다.
- 만들어진 Object(객체)가 Controller 호출 시 메서드의 파라미터로 전달됩니다.
- `supportsParameter()`를 사용하는 다양한 `ArgumentResolver` 구현체
실제 동작 순서
1. Spring은 컨트롤러 메서드 파라미터를 분석하고, `HandlerMethodArgumentResolver` 구현체들이 저장된 리스트를 순회하면서, `supportsParameter()`를 호출하여 검증합니다.
for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
return resolver.resolveArgument(...); // 여기서 파라미터 값을 만들어냄
}
}
2. 어노테이션 또는 파라미터에 대한 resolver가 맞는지 검증합니다.
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
- `MethodParameter parameter` 안에, 해당 컨트롤러 메서드의 파라미터 정보 전체가 들어있습니다.
- 특정 Resolver의 `supportsParameter()`가 ` parameter` 정보를 통해 확인한 후, 맞으면 `true`를 반환합니다.
3. true가 반환 된다면, 그 후 특정 Resolver는 `resolveArgument()` 내부에서 다음 코드를 실행합니다.
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
@Nullable
Object resolveArgument(
MethodParameter parameter,
@Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
@Nullable WebDataBinderFactory binderFactory
) throws Exception;
}
- 실제로 파라미터 값을 생성하여 반환하는 역할을 합니다.
- 파라미터를 어떻게 만들어야 할지 구체적인 로직이 들어갑니다.
파라미터 | 설명 |
`MethodParameter parameter` | 처리 중인 파라미터 (타입, 어노테이션 등 포함) |
`ModelAndViewContainer mavContainer` | Model이나 View 이름을 담고 있는 컨테이너. 주로 `@ModelAttribute`나 `Model` 파라미터가 있을 때 사용됩니다. |
`NativeWebRequest webRequest` | `HttpServletRequest`와 같은 웹 요청 객체를 래핑한 객체 |
`WebDataBinderFactory binderFactory` | 바인딩과 검증을 위한 `WebDataBinder`를 생성해주는 팩토리. `@Valid`, `@InitBinder` 등을 처리할 때 사용합니다. |
ReturnValueHandler
정의 :
컨트롤러 메서드의 리턴값을 HTTP 응답으로 변환해주는 컴포넌트입니다.
컨트롤러가 반환한 값을 Model, View, JSON, HTTP 응답 본문 등으로 변환합니다.
✨ 리턴 타입, 어노테이션 등에 따라 알맞은 Handler가 선택되어 호출됩니다.
ReturnValueHandler 구현체 종류 :
리턴 타입 또는 어노테이션 | 해당 Handler 클래스 | 설명 |
`@ResponseBody` | RequestResponseBodyMethodProcessor | 객체를 JSON 또는 XML로 직렬화하여 HTTP 응답 body에 작성 |
`ResponseEntity<T>` | HttpEntityMethodProcessor | 상태 코드, 헤더, body 모두 직접 설정하여 응답 가능 |
`HttpEntity<T>` | HttpEntityMethodProcessor | 위와 동일하지만 상태 코드는 기본값 사용 |
`ModelAndView` | ModelAndViewMethodReturnValueHandler | 명시적으로 Model과 View 이름을 포함한 객체를 리턴 |
`String` (View 이름) | ViewNameMethodReturnValueHandler | 리턴된 문자열을 View 이름으로 간주 (JSP, Thymeleaf 등) |
`Model` / `Map` | ModelMethodProcessor | Model 객체 자체를 반환 (주로 forward 용) |
`@ModelAttribute` (리턴값에 사용) | ModelAttributeMethodProcessor | 객체를 Model에 추가하고 View로 전달 |
`void` (리턴 없음) | VoidMethodReturnValueHandler | 뷰 이름을 명시하지 않으면 요청 URL로부터 View 추정 |
`StreamingResponseBody`, `ResponseBodyEmitter`, `SseEmitter` 등 | StreamingResponseBodyReturnValueHandler 외 | 비동기 스트리밍 방식으로 HTTP 응답 전송 |
- 모든 Handler 클래스들은 `HandlerMethodReturnValueHandler` 인터페이스를 구현하고 있습니다.
예시 :
@GetMapping("/user")
@ResponseBody
public User getUser() {
return new User("Tom");
}
- 리턴 타입 : `User`, 어노테이션 : `@ResponseBody`
- 처리 Handler : ` RequestResponseBodyMethodProcessor`
HandlerMethodReturnValueHandler
- `ReturnValueHandler`의 실제 이름
- resolver 클래스들은 이 인터페이스를 구현한 형태입니다.
- 이 인터페이스를 구현하여, 커스텀하게 파라미터를 만들 수 있습니다. (확장)
- 다양한 ReturnValueHander 구현체
동작 방식
1. Spring은 컨트롤러 메서드의 리턴 타입을 분석합니다.
for (HandlerMethodReturnValueHandler handler : returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
handler.handleReturnValue(...); // 여기서 리턴값 처리
break;
}
}
- `HandlerMethodReturnValueHandler` 구현체들이 저장된 리스트를 순회하면서
- `supportsReturnType()`을 호출하여 이 핸들러가 해당 리턴값을 처리할 수 있는지 확인합니다.
2. 어노테이션 또는 리턴 타입에 따라 `supportsReturnType()`이 호출됩니다.
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return returnType.hasMethodAnnotation(ResponseBody.class);
}
- `MethodParameter returnType` : 컨트롤러 메서드의 리턴 타입 정보를 담고 있습니다.
- 조건이 맞으면 `true` 반환 → 해당 핸들러가 처리할 대상입니다.
3. `true`가 반환되면, 해당 핸들러의 `handleReturnValue()`가 호출됩니다.
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(
@Nullable Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest
) throws Exception;
}
- 이 메서드가 컨트롤러 메서드의 리턴값을 적절한 방식으로 HTTP 응답에 바인딩합니다.
- 예: JSON 변환, View 이름 설정, Model에 데이터 추가 등
파라미터 | 타입 | 설명 |
`returnValue` | `@Nullable Object` | 컨트롤러 메서드가 반환한 실제 값입니다. 예: User, String, ResponseEntity, 등. |
`returnType` | `MethodParameter` | 리턴값에 대한 메서드 파라미터 정보 객체입니다. 어노테이션(@ResponseBody, @ModelAttribute)이나 제네릭 타입 등의 정보도 포함됩니다. |
`mavContainer` | `ModelAndViewContainer` | 모델, 뷰 이름, 처리 완료 여부 등을 담고 있는 컨테이너입니다. View 렌더링을 제어하는 데 사용됩니다. 예: mavContainer.setViewName("home") |
`webRequest` | `NativeWebRequest` | HTTP 요청 및 응답에 접근할 수 있는 추상화된 객체입니다. 내부적으로 HttpServletRequest, HttpServletResponse에 접근 가능하며, Spring Web 전체에서 공통적으로 사용됩니다. |
'Spring' 카테고리의 다른 글
[Spring] Custom HttpMessageConvert 생성 & 등록을 위한 WebMvcConfigurer 활용 (0) | 2025.06.06 |
---|---|
[Spring] Spring MVC, RequestMappingHandlerAdapter의 요청 및 응답 처리 과정 : HttpMessageConverter (0) | 2025.06.06 |
[Spring] Spring MVC, RequestMappingHandlerAdapter의 요청 및 응답 처리 과정 (0) | 2025.06.05 |
[Spring] Spring URI 매핑 방식의 진화: 초기 Bean 이름 매핑부터 어노테이션 기반까지 (0) | 2025.05.26 |
[Spring] 의존 관계 주입 방법 4가지 (2) | 2025.05.23 |