본문 바로가기
Back End/Spring

[Spring] 요청 매핑 핸들러 어뎁터의 구조

by SolaKim 2023. 8. 8.

 

 

Argument Resolver

 

애노테이션 기반 컨트롤러를 처리하는 RequestMappingHandlerAdapter는 바로 이 ArgumentResolver를 호출해서 컨트롤러(핸들러)가 필요로 하는 다양한 파라미터의 값(객체)를 생성한다. 

그리고 이렇게 파라미터의 값이 모두 준비되면 컨트롤러를 호출하면서 값을 넘겨준다.

 

public interface HandlerMethodArgumentResolver {
	boolean supportsParameter(MethodParameter parameter);
    
    @Nullable
    Object resolveArgument(MethodParameter parameter, 
    @Nullable ModelAndViewContainer mavContainer, 
    NativeWebRequest webRequest, 
    @Nullable WebDataBinderFactory binderFactory) throws Exception;
}

동작 방식을 살펴보자

ArgumentResolver의 supportsParameter()를 호출해서 해당 파라미터를 지원하는지 체크하고, 지원하면 resolveArgument()를 호출해서 실제 객체를 생성한다. 그리고 이렇게 생성된 객체가 컨트롤러 호출시 넘어가는 것이다.

 

 

ReturnValueHandler

 

이것은 ArgumentResolver와 비슷한데, 응답값을 변환하고 처리한다.

컨트롤러에서 String으로 뷰 이름을 반환해도, 동작하는 이유가 바로 이것 덕분이다.

 

 

그래서 HTTP 메시지 컨버터는 도대체 어디쯤에서 작동하는것일까?

 

 

요청의 경우 

@RequestBody를 처리하는 ArgumentResolver가 있고, HttpEntity를 처리하는 ArgumentResolver가 있다.

이 ArgumentResolver들이 HTTP 메시지 컨버터를 사용해서 필요한 객체를 생성하는 것이다.

응답의 경우

@ResponseBody와 HttpEntity를 처리하는 ReturnValueHandler가 있다. 그리고 여기서 HTTP 메시지 컨버터를 호출해서 응답 결과를 만든다.

 

 

 

지금까지 스프링 MVC를 공부해보면서 동작과정에 대해서 순서대로 간단히 정리해보고자한다.

0. 스프링 부트 구동 시점에서 스프링 컨테이너와 서블릿 컨테이너는 각각 필요한 기본 빈들을 생성하고, 필요한 초기화 작업과 DI 작업을 수행

1. 클라이언트로부터 URL 호출 시, 서블릿 컨테이너가 request를 파싱한다. 그 후 HttpServletRequest와 Response 객체를 생성한 뒤, 파싱된 메세지를 HttpServletRequest에 전달한다.

2. 쓰레드가 DispatcherServlet 객체의 service()를 호출한다. (service()는 실제로 부모 클래스에서 오버라이딩 되어있고 그 내부에서 중요한 메서드인 doDispatch()가 호출된다)

3. DispatcherServlet은 미리 초기화 해둔 handlerMappings의 handlerMapping 구현 클래스를 순서대로 하나씩 꺼내와 검사하는데, 1순위인 RequestMappingHandlerMapping 클래스의 조회 전략은 @Controller 클래스 중, 메서드 레벨에 @RequestMapping이 붙어있고, request의 URL정보를 토대로 일치하는지 검사한다. 만약 있다면 해당 핸들러(컨트롤러)를 반환한다. 없다면 다음 순위로..

4. 해당 핸들러를 getHandlerAdapter()를 통해서 해당 핸들러를 지원하는 어댑터가 있다면 해당 어댑터를 반환하여 HandlerAdapter 에 할당하고, 지원하는 어댑터가 없는 경우 서블릿 예외를 던진다.

5. HandlerAdapter의 handler()를 수행하는데 실제 컨트롤러 메서드를 호출하기 전에, 해당 메서드가 필요로 하는 매개변수 정보를(@RequestBody인지, HttpEntity인지) ArgumentResolver에게 제공하고, 각각에 특화된 Http메시지 컨버터를 사용해서 필요한 객체를 생성한다.

6. handlerAdapter가 컨트롤러를 호출해서 로직을 수행한다.

7. 컨트롤러가 결과값을 반환한다.

7-1. 메서드 레벨에 @RequestBody가 붙어있다면 ReturnValueHandler가 HttpMessengerConverter를 이용해서 반환값을 응답 메세지 바디부에 실어서 ViewResolver등을 거치지 않고 즉시 요청 송신자에 반환한다. (뷰 없이 바로 반환)

7-2. 위의 경우가 아니면, ReturnValueHandler는 반환 값의 타입에 따라 적절한 HttpMessengerConverter를 통해 응답 메세지를 생성 후, ViewResolver가 동작하는데 이는 View 객체를 생성하고 DispatcherServlet가 이를 이용하여 render()하고 최종적으로 클라이언트에게 반환한다.

 

 

 

 

🤩 학습한 내용 + 참고 그림 출처 : 김영한님의 스프링 MVC1

'Back End > Spring' 카테고리의 다른 글

[Spring] 스프링 MVC 기본 기능  (0) 2023.08.07
[Spring] 로깅 logging  (0) 2023.08.07
[Spring] 스프링 MVC 구조  (0) 2023.08.07
[Spring] 서블릿(servlet) aka. MVC 구버전  (0) 2023.08.03
[Spring] 웹 애플리케이션의 이해...  (0) 2023.08.01