Spring

@RestController 와 @Controller 의 차이

@RestController 와 @Controller 의 차이점

간단하게 얘기하자면 @RestController 는 @Controller + @ResponseBody 입니다.

그렇다면 차이는 @ResponseBody 라는 어노테이션이 더해진 것인데, 스프링은 이 어노테이션이 있는 것만으로 어떻게 구분하고 응답 본문에 메시지를 넣어줄까요?

 

스프링 부트의 자동 설정을 사용한다면 HttpMesageConverter 의 구현체 중 MappingJackson2HttpMessageConverter 를 사용하여 json 형태로 메시지를 컨버팅하여 body에 넣어줍니다. 스프링이 어떤 메시지 컨버터를 선택하는 지, 또한 view 를 선택하는 경우는 어떠한 경우인지에 대해 알아보겠습니다.

 

HandlerAdapter

스프링 공식문서의 내용에 따르면 HandlerAdapter 가 어노테이션이 달린 controller에서 view 가 아닌 response 를 랜더링 하는 역할을 한다고 쓰여있습니다.

이를 상기하고 HandlerAdapter 의 처리과정에 대해 살펴보겠습니다.

 

DispatcherServlet

외부에서 요청이 오면 DispatcherServlet 이 요청을 받아 처리합니다.

DispatcherServlet 은 doService -> doDispatch 메서드를 실행하고, 그 안에서 HandlerAdapter 를 가져와 handle 메서드를 실행시킴으로써 렌더링 과정을 수행합니다.

DispatcherServlet 입장에서 본 HandlerAdapter

RestController

DispatcherServlet 은 HandlerAdapter 인터페이스를 통해 결과를 받습니다.

HandlerAdapter 의 내부에서 일어나는 일을 다음 그림과 함께 알아보겠습니다.

사실 조금 더 복잡하지만 어느정도 간략화를 하였습니다.

기본설정으로 RequestMappingHandlerAdapter 를 선택하여 실행됩니다.

RequestMappingHandlerAdapter 는 HandlerMethodReturnValueHandlerComposite 에게 반환할 값에 대한 처리를 요청합니다. HandlerMethodReturnValueHandlerComposite 는 이름처럼 유연한 설계를 위해 composite 패턴을 사용하여 핸들러들을 가지고, 그 중에서 어떤 핸들러에게 처리를 맡길지 결정합니다.

그 중, RequestResponseBodyMethodProcessor 의 supportsReturnType 을 보겠습니다.

@Override
public boolean supportsReturnType(MethodParameter returnType) {
	return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
			returnType.hasMethodAnnotation(ResponseBody.class));
}

익숙한 ResponseBody 가 보입니다. RequestResponseBodyMethodProcessor 는 ResponseBody 어노테이션이 클래스나 메서드에 달려있으면 처리할 수 있습니다.

또한 메시지 컨버터를 가지고 있습니다.

이 중 우리가 쓰고자 했던 MappingJackson2HttpMessageConverter 가 등록되어 있습니다. RequestResponseBodyMethodProcessor 는 메시지 컨버터를 사용하고, ModelAndViewContainer 에 requestHandled 필드를 true 로 변경합니다.

이 필드가 true 이면 ModelAndView 를 null 로 리턴합니다. 따라서 DispatcherServlet 은 null 인 ModelAndView 를 보고, 이미 렌더링 되었다고 판단하게 됩니다.

Controller

Controller 의 경우 return type 에 따라 핸들러가 바뀔 수 있습니다.

String 으로 return 할 경우 ViewNameMethodReturnValueHandler 를 선택합니다.

@Override
public boolean supportsReturnType(MethodParameter returnType) {
  Class<?> paramType = returnType.getParameterType();
  return (void.class.equals(paramType) || String.class.equals(paramType));
}

해당 핸들러는 ModelAndView 에 반환받은 String 으로 view name 을 지정하고 반환합니다.

DispatcherServlet 은 render 메서드에서 ViewResolver 를 선택하여 렌더링합니다.

'Spring' 카테고리의 다른 글

Swagger - API 문서 자동화  (0) 2020.09.07
[setting] Root context, Servlet context 차이점  (0) 2017.07.23
[web] textarea 줄바꿈  (0) 2017.07.16