⚙️ RequestMappingHandlerAdapter란?
@RequestMapping계열(@GetMapping,@PostMapping등) 컨트롤러 메서드를 실행하는 핵심 어댑터- 내부적으로 두 컴포지트를 보유:
HandlerMethodArgumentResolverComposite(파라미터 바인딩)HandlerMethodReturnValueHandlerComposite(반환값 처리)- “어떤 파라미터를 어떻게 만들지?”, “이 반환값을 어떻게 응답으로 보낼지?”를 각각 위임
🧩 Spring MVC 구조

→ 요청 데이터가 변환됨 (HttpMessageConverter)
→ Controller에 전달되는 HandlerAdapter와 Handler 사이에서 어떤 일이 발생함
🧩 RequestMappingHandlerAdapter

→ @RequestMapping을 처리하는 HandlerAdapter의 구현체
→ @PostMapping, @GetMapping, @PutMapping, @PatchMapping, @DeleteMapping 등은 모두 @RequestMapping의 일종
🧲 ArgumentResolver란?
- 컨트롤러 메서드 각 파라미터를 적절한 객체로 변환 후 주입
- 예)
@RequestParam,@PathVariable,@RequestBody,HttpServletRequest,Model등
✍️ 핵심 메서드
boolean supportsParameter(MethodParameter parameter); // 내가 이 파라미터 처리가 가능한지?
Object resolveArgument(MethodParameter parameter, ...); // 실제 값 만들어서 반환
🧰 자주 쓰는 내장 Resolver 예시
RequestParamMethodArgumentResolver → @RequestParamPathVariableMethodArgumentResolver → @PathVariableRequestHeaderMethodArgumentResolver → @RequestHeaderRequestResponseBodyMethodProcessor → @RequestBody (내부에서 HttpMessageConverter 사용)ModelAttributeMethodProcessor → @ModelAttributeAuthenticationPrincipalArgumentResolver → @AuthenticationPrincipalPageableHandlerMethodArgumentResolver → Pageable📍 동작 포인트
supportsParameter == true인 첫 Resolver가 resolveArgument() 수행🎁 ReturnValueHandler란?
- 컨트롤러 반환값을 HTTP 응답에 맞게 변환/가공
- 예)
ModelAndView, 뷰 이름 문자열,@ResponseBody,HttpEntity<>, 스트리밍 등
✍️ 핵심 메서드
boolean supportsReturnType(MethodParameter returnType); // 처리가 가능한지?
void handleReturnValue(Object returnValue, ...); // 실제 응답으로 변환
🧰 내장 핸들러 예시
ModelAndViewMethodReturnValueHandler → ModelAndViewViewNameMethodReturnValueHandler → String(뷰 이름)HttpEntityMethodProcessor → HttpEntity / ResponseEntityRequestResponseBodyMethodProcessor → @ResponseBody(여기도 HttpMessageConverter 사용)ResponseBodyEmitter*, StreamingResponseBody*, Callable*, DeferredResult* 등 비동기/스트리밍📍 동작 포인트
🐞 자주 만나는 예외 & 디버깅
| 예외/상태 | 시점 | 원인 | 해결 |
|---|---|---|---|
MissingServletRequestParameterException (400) | @RequestParam | 필수 파라미터 누락 | required=false/기본값/검증 |
MethodArgumentTypeMismatchException (400) | 변환 단계 | 타입 변환 실패 | 타입 확인, 포맷터/컨버터 |
MethodArgumentNotValidException (400) | @Valid | 바인딩/검증 실패 | 에러 응답 표준화 |
HttpMessageNotReadableException (400) | @RequestBody | 바디 JSON 문법/매핑 실패 | JSON/DTO 점검 |
HttpMediaTypeNotSupportedException (415) | 읽기 | Content-Type 불일치 | 올바른 헤더/consumes |
HttpMediaTypeNotAcceptableException (406) | 쓰기 | Accept 불일치 | 올바른 헤더/produces |
🧠 요약 정리
| 항목 | RequestMappingHandlerAdapter | ArgumentResolver | ReturnValueHandler |
|---|---|---|---|
| 기능 | 컨트롤러 메서드 실행 엔진 | 메서드 파라미터를 객체로 주입 | 반환값을 응답 형식으로 변환 |
| 동작 시점 | 핸들러 결정 후 전체 실행 단계 | 컨트롤러 호출 직전(파라미터별) | 컨트롤러 호출 직후 |
| 선택 기준 | 해당 없음(고정) | supportsParameter(MethodParameter) | supportsReturnType(MethodParameter) |
| 핵심 메서드 | (컴포지트 보유) | resolveArgument(...) | handleReturnValue(...) |
| 예시 | — | @RequestParam, @PathVariable, @RequestBody, HttpServletRequest | ModelAndView, String(view), @ResponseBody, HttpEntity |
| 컨버터 연계 | 간접 | @RequestBody → 내부에서 HttpMessageConverter.read | @ResponseBody/HttpEntity → HttpMessageConverter.write |
| 확장 | — | 커스텀 Resolver + addArgumentResolvers | 커스텀 Handler + extendHandlerExceptionResolvers 등(일반적으론 ResponseBodyAdvice 권장) |
| 주의 | — | 적용 범위 과도 확장 주의(명확한 애노테이션/타입 매칭) | 전역 래핑은 ResponseBodyAdvice가 더 간결 |