Lined Notebook

[스프링 MVC - 백엔드 웹 개발 기술] 17. HTTP 메시지 컨버터(Message Converter)

by ymkim

01. 요청 매핑 핸들러 어뎁터 구조

RequestMappingHandlerAdapter

  • HTTP 메시지 컨버터는 스프링 MVC의 어느곳에서 사용되는 것일까?
  • 위 그림을 봤을대 HTTP 메시지 컨버터가 사용되는 곳은 보이지 않는다
  • 모든 비밀은 어노테이션 기반의 컨트롤러인 @RequestMapping처리하는 핸들러 어댑터RequestMappingHandlerAdaptor(요청 매핑 핸들러 어뎁터)에 있다

01-1. RequestMappingHandlerAdaptor 동작 방식

ArgumentResolver(요청시)

RequestMapping 핸들러 어댑터 → ArgumentResolver에게 문의(파라미터 존재?) → 핸들러 전달

@GetMapping("/test1")
public ResponseEntity<?> test01(HttpServletRequest request, HtttpServletResponse response) {
    return ResponseEntity.ok("ok");
}

@PostMapping("/test2")
public ResponseEntity<?> test02(@RequestBody Member member) {
    return ResponseEntity.ok("ok");
}

@PostMapping("/test3")
public ResponseEntity<?> test03(HttpEntity httpEntity) {
    return ResponseEntity.ok("ok");
}

@PostMapping("/test4")
public ResponseEntity<?> test03(@ModelAttribute Member member) {
    return ResponseEntity.ok("ok");
}
 

Method Arguments :: Spring Framework

JDK 8’s java.util.Optional is supported as a method argument in combination with annotations that have a required attribute (for example, @RequestParam, @RequestHeader, and others) and is equivalent to required=false.

docs.spring.io

  1. 생각하면, 어노테이션 기반의 컨트롤러는 매우 다양한 파라미터를 유연하게 사용할 수 있었다
    1. 즉, 컨트롤러의 파라미터 입력란에 아래와 같은 다양한 객체, 어노테이션 등을 사용할 수 있다는 의미다
  2. HttpServletRequest/Response, Model, @RequestParam, @ModelAttribute 와 같은 어노테이션 그리고 @RequestBody, HttpEntity와 같은 HTTP 메시지 처리하는 부분까지 매우 유연하게 선언이 가능하다는 것을 볼 수 있다
    1. 또한 위와 같은 파라미터를 앞에서 누군가가 만들어서 컨트롤러에 전달해줘야 했다?
    2. 누가 전달해주는거지? 3번 내용을 이어서 보자
  3. 위와 같이 파라미터를 유연하게 처리할 수 있는 이유가 ArgumentResolver 덕분이다
    1. DispatcherServlet → 요청 매핑 핸들러 어댑터(RequestMappingHandlerAdapter) → ArgumentResolver에게 해당 파라미터 (ex : @RequestBody Member member) 너가 처리 가능? → OK 처리 가능 → 핸들러에게 전달 해주는 플로우를 우리는 위에서 봤다
  4. 어노테이션 기반 컨트롤러를 처리하는 RequestMappingHandlerAdaptor 는 바로 이 ArgumentResolver 를 호출하여 컨트롤러(핸들러)가 필요로 하는 다양한 파라미터 값(객체)을 생성해준다. 또한 이렇게 파라미터의 값이 모두 준비되면 컨트롤러를 호출하면서 값을 넘긴다

스프링은 30개가 넘는 ArgumentResolver를 기본적으로 제공한다.
어떤 종류가 있는지 확인만 해보자.

HandlerMethodArgumentResolver

package org.springframework.web.method.support;

import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;

/**
 * Strategy interface for resolving method parameters into argument values in
 * the context of a given request.
 *
 * @author Arjen Poutsma
 * @since 3.1
 * @see HandlerMethodReturnValueHandler
 */
public interface HandlerMethodArgumentResolver {

	boolean supportsParameter(MethodParameter parameter);

	@Nullable
	Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}

HandlerMethodArgumentResolver 는 위와 같이 인터페이스로 구현이 되어 있으면 하위 구현체에서 해당 인터페이스를 구현해 사용하는 방식이다

동작 방식

  • ArgumentResolversupportParameter() 를 호출해서 해당 파라미터 지원 여부를 체크
  • 지원하면 resolveArgument() 호출 후 실제 객체를 생성 (HttpServletRequest, Response, DTO 등등..)
  • 후에 생성된 객체를 컨트롤러 호출 시 넘기는 작업을 거친다
  • 원한다면 해당 인터페이스(HandlerMethodArgumentResolver)를 직접 구현하여 ArgumentResolver를 만들 수 있다

ReturnValueHandler(응답시)

  • HandlerMethodReturnValueHandler를 줄여서 ReturnValueHandler 라 부른다
  • ArgumentResolver 와 비슷한데 ReturnValueHandler은 ‘응답 값’을 변환하고 처리한다
  • ex) 컨트롤러에서 String으로 뷰 이름으로 반환해도, 동작하는 이유가 ReturnValueHandler 덕분이다
    • ModelAndView, @ResponseBody, HttpEntity, String

02. HTTP 메시지 컨버터

02-1. HTTP 메시지 컨버터 위치

  • HTTP 메시지 컨버터는 ArgumentResolver, ReturnValueHandler 두곳에서 모두 사용이 된다
    • 요청 파라미터 검증 후 객체를 생성하는 경우, 응답하는 경우 둘다 사용
  • HTTP 메시지 컨버터는 어디쯤에 있는가?
    • 중요 : @RequestBody, @ResponseBody, HttpEntity
      • ArgumentResolver + HTTP Message 컨버터 // ReturnValueHandler + HTTP Message 컨버터 사용
    • HTTP 메시지 컨버터를 사용하는 @RequestBody도 결국에는 컨트롤러의 파라미터 값에 사용이 된다
    • @ResponseBody의 경우도 컨트롤러의 반환 값이 이용이 된다
  • 요청의 경우 : @RequestBody, HttpEntity를 처리하는 ArgumentResolver 존재.
    • 해당 ArgumentResolver 들이 HTTP 메시지 컨버터를 사용하여 필요한 객체를 생성하는 것
  • 응답의 경우 : @ResponseBody, HttpEntity를 처리하는 ReturnValueHandler 존재.
    • 그리고 여기에서 HTTP 메시지 컨버터를 호출해서 응답 결과를 만든다
  • @RequestBody, @ResponseBody 존재
    • RequestResponseBodyMethodProcessor(ArgumentResolver)
  • HttpEntity 존재
    • HttpEntityMethodProcessor(ArgumentResolver)

02-2. 확장

스프링에서는 다음을 모두 인터페이스로 제공, 하여 필요하면 언제든 기능 확장이 가능하다

  • HandlerMethodArgumentResolver
  • HandlerMethodReturnValueHandler
  • HttpMessageConverter

02-3. 스프링은 대부분의 기능을 제공하기에 확장할 일이 많지 않음

  • 기능 확장은 WebMvcConfigure를 상속받아서 스프링 빈으로 등록하면 된다
  • 실제 자주 사용하지는 않으니 실제 기능 확장이 필요한 경우 사용한다
@Bean
public WebMvcConfigurer webMvcConfigurer() {

		@Override
    public void addInterceptors(InterceptorRegistry registry) {
        WebMvcConfigurer.super.addInterceptors(registry);
    }

}

블로그의 정보

기록하고, 복기하고

ymkim

활동하기