[Project] Controller 생성 & API 호출 (2) - EP03

반응형

이번 시리즈에서는 스프링 부트로 프로젝트를 처음부터 생성 및 구축해보도록 하겠습니다.  

# 목차 
1. 스프링 부트 프로젝트 생성 & 실행 - EP01
2. Controller 생성 & API 호출 (1) - EP02
3. Controller 생성 & API 호출 (2) - EP03

DispatcherServlet

이전글에 이어 다음으로 살펴볼 클래스는 DispatcherServlet 입니다.  
앞단에서 HTTP request 에 대한 여러 Filter 처리가 완료된 후에는 
DispatcherServlet 이 호출되어 실제로 해당 request 에 mapping 된 method 를 호출하게 됩니다. 

위 Debugger Stack 상으로는 HttpServlet 이라고 표기되어 있지만.

DispatcherServlet 의 상위 클래스 상속구조가 다음과 같기 때문에.
HttpServlet / FrameworkServlet 클래스 내부 메서드가 호출될 수 있는 구조입니다. 

위에서 각 Servlet 클래스에 대한 자세한 설명은 생략하겠습니다.

간단히 GenreicServlet 은 일반적인 Servlet 을 통칭하고..
HttpServlet 은 HTTP 전용으로 사용하기 위한 GenricServlet 이며.
FrameworkServlet 은 Spring 전용으로 사용하기 위한 HttpServlet 으로만 이해하고 넘어가겠습니다..

이 중 DispatcherServlet 은 HTTP request 에 대한 중앙 집중 처리를 전담해주는 친구로..

그림으로 간단히 정리하면 다음과 같이 
HTTP request 가 들어오면 Servlet Container 가 관리하는 여러 Servlet 중
해당 요청에 맞는 Servlet (일반적으로 Controller 를 통칭..) 을 찾아서 request 를 처리하도록 요청합니다.

조금 더 자세히 살펴보면..

HttpServlet

먼저 HttpServlet 의 service 메서드를 통해 ServletRequest / ServletResponse 객체가 (사용자 요청)
HttpServletRequset / HttpServletResponse 객체로 변환됩니다. 

ServletRequest / ServletReponse 와 HttpServletRequest / HttpServletResponse 의 차이점은 다음과 같습니다. 

참고 : https://stackoverflow.com/questions/57644369/servletrequest-is-a-interface-or-a-classwhat-is-the-difference-between-servletr

요약하자면 ServletRequest / ServletResponse 는 Protocol 독립적인 interface 이며
HttpServletRequest / HttpServletResponse 는 HTTP Protocol 을 위해 사용되는 interface 입니다. 

즉, 다음과 같이 웹 브라우저로 요청한 /hello request 는 HTTP Protocol 을 사용하므로.
이를 처리하기위해 ServletRequest / ServletResponse 를 
HttpServletRequest / HttpServletResponse 로 변환하는 것으로 이해하면 될 것 같습니다. 

FrameworkServlet

다음으로는 FrameworkServlet 의 service 메서드가 호출되는데
PATCH 요청의 경우에만 super 클래스인 HttpServlet 의 service 가 아닌 
FrameworkServlet 클래스의 service 메서드를 호출합니다.

이는..  PATCH 메서드가 비교적 최근에 추가되었기 때문에.
HttpServlet 의 service 메서드에는 PATCH 요청에 대한 처리를 하도록 설계되어 있지 않기 때문인 것으로 생각됩니다. (아마도..?)

실제로 HttpServlet 의 service 메서드를 살펴보면 다음과 같이 PATCH 요청에 대해서만
어떻게 처리할 것인지에 대해 구현이 된 내용이 없는 것을 알 수 있습니다. (GET / POST / DELETE / PUT 등 은 존재..)

결론적으로.. HttpServlet 에 정의되어 있지 않은 PATCH 요청이나..

아니면.. 정의되어 있는 GET / POST / PUT / DELETE / OPTIONS / TRACE 등의 요청이던지 간에..

FrameworkServlet 의 processRequset 메서드를 호출해 request 에 대한 처리를 위임(delegate) 하게 됩니다. 

RequestHanlderMapping

이후 DispatcherServlet 에서 getHandler 메서드를 호출해 
HTTP request 를 처리하기 위해 어떠한 컨트롤러 & 메서드(Handler)를 사용할 것인지를 determine 하게 되는데.   

이 때 프로젝트 별 어떠한 Mapping 전략을 사용하고 있느냐에 따라 
아래와 같이 Hanlder 를 찾아주는 역할을 하는 HanlderMapping 구현체가 달라지게 됩니다. 

현재 제 프로젝트에서는 다음과 같이 RequestMapping 전략을 사용하고 있기 때문에.
(@GetMapping 은 @RequestMapping(method = RequestMethod.GET) 와 동일)

아래의 getHanlder 메서드의 내부에서 HttpRequestMappingHandler 구현체를 사용해 
HTTP request 에 대한 MappingHandler 를 찾게 되고.. 

결과적으로 return 받은 MappingHanlder 는 
다음과 같이 어떤 Contoller 에 어떤 Method 를 수행해야 되는지에 대한 정보가 담겨 있게 됩니다. 

간단히, HanlderMethod 란 HTTP request 를 처리하기 위한 Controller & Method 에 대한 정보라고 이해하면 될 것 같습니다. 

RequestHandlerMappingAdapter

자 이제.. 오랜 여정 끝에.. HTTP request 를 처리하기 위한 Controller 와 Method 정보를 알아냈으니.. 
이제 해당 Method 를 실행한 뒤 결과값을 return 해주면 되는데.
   
이 때 에도 직접 해당 요청을 수행하는 것 이 아닌.
Adpater 패턴을 적용한 RequestMappingHanlderAdpater 를 호출해 작업을 수행하게 됩니다.. 🤦🏻‍♂️ 

Adpater 패턴을 사용한 이유는 아마도..
어떠한 Mapping 전략을 사용하던지 간에.. 
동일하게 시스템이 동작할 수 있도록 구현되어 있는 것 같습니다. 

참고 : https://yaboong.github.io/design-pattern/2018/10/15/adapter-pattern/

ServletInvocableHanlderMethod

RequestMappingHanlderAdpater가 호출되면 내부적으로는
RequestMappingHanlderMapping 이 찾아준 HanlderMethod 를
ServletInvocableHandlerMethod 로 Wrapping 한 뒤 해당 HanlderMethod 를 invoke (수행) 합니다. 

ServletInvocableHandlerMethod 는 다음과 같은 상속 구조를 가지고 있는데.

해당 클래스의 설명을 보면 아마도?..
HandlerMethodReturnValueHandler 를 사용해 return value 를 handle 하고
method-level 로 reponse status 를 설정하기 위해 사용하는 것 같습니다. 

ServletInvocableHandlerMethod 는 결론적으로 doInvoke 메서드를 통해 
HanlderMethod (요청 HTTP request 를 처리하기 위한 Controller 의 Method) 를 수행하게 되는데

Reflection

이때 Method 를 수행하기 위해 내부적으로는 Reflection 을 사용하게됩니다.

Reflection 는 간단히.. 객체를 통해 클래스의 정보를 분석해 내는 방법이라고만 이해하고 
넘어가도록 하겠습니다. (아직 잘 모르는 분야 입니다. ㅠㅠ)

ServletInvocableHanlderMethod

다음으로.. 진짜 진짜 최종으로..
드디어 HelloController Stack 이 호출되게 되고.. 

GET /hello 요청과 mapping 되는 hello() 메서드가 수행이 되게 됩니다.. 

자.. 이렇게 간단한게 /hello 요청이 호출되는 과정에 대해 알아보았습니다. 😭 
다음글에서는 위 요청에 대한 결과값이 어떻게 return 되는지에 대해 알아보도록 하겠습니다. 


결론

여러 Filter 처리가 완료된 HTTP request 에 대해 DispatcherServlet 이 
해당 request 를 처리하기 위한 Servlet 을 찾아 작업을 요청하기 위해..

1. ServletRequset / ServletResponse 를 HTTP 요청 규격에 맞도록 
   HttpServletRequest / HttpServletResponse 로 변환하고 (HttpServlet)

2. HttpServlet 규격에는 PATCH 메서드가 구현되어 있지 않으므로.. 
   PATCH 요청일 경우에만 FrameworkServlet 의 service 메서드를 직접 호출하고, 
   나머지 요청들은 HttpServlet 에 구현되어 있는 service 메서드를 호출해 요청을 처리하며

3. 프로젝트의 Mapping 전략별 MappingHanlder 를 사용해 (현 프로젝트 기준 RequsetMappignHandler) 
   해당 HTTP request 를 처리하기 위한 HandlerMethod (Controller & Method 정보) 를 알아내고.

4. 알아낸 HandlerMethod (Controller & Method 정보) 를 수행하기 위해 
   Adapter 패턴을 적용한 HanlderMappingAdapter 를 호출해 작업을 위임하며. 

5. 이 때 HanlderMappingAdapter 는 해당 작업을 수행하기 위해 내부적으로 Reflection 
   (객체를 통해 클래스의 정보를 분석해 내는 방법) 을 사용하게 된다. 

로 이해할 수 있습니다. 

반응형

댓글

Designed by JB FACTORY