스프링을 사용하면 기본적으로 알아야할 DispatcherServlet에 대해서 알아보겠습니다.
🟧 01. 디스패처 서블릿 (DispatcherServlet)에 대해서
Spring MVC와 같은 많은 웹 프레임워크들은 Front Controller Pattern을 중심으로 설계됐다.
DispatcherServlet은 요청 처리에 대한 알고리즘을 제공하고 있다.
즉, Http Protocol로 오는 모든 요청을 적절한 컨트롤러에게 위임해주는 프론트 컨트롤러(Front Controller)가 DispatcherSevlet이다.
🟧 02. 프론트 컨트롤러 (Front Controller)가 뭔데 ?
과거에는 클라이언트가 요청을 보내면 각 요청에 맞는 컨트롤러에서 처리한다.
때문에 공통 로직이 중복되는 단점이 있다.
이러한 공통 로직 중복 코드를 해결하기 위해서 나온 것이 프론트 컨트롤러(Front Controller)이다.
프론트 컨트롤러는 공통 로직을 처리하고 요청에 맞는 컨트롤러에게 작업을 넘겨준다.
프론트 컨트롤러는 웹 애플리케이션에서 등장하는 패턴이다.
프론트 컨트롤러 패턴은 공통 로직을 처리해준다는 점이 가장 중요하다.
여기서 프론트 컨트롤러를 디스패처 서블릿(DispatcherServlet)이라고 부르겠다.
🟧 03. 디스패처 서블릿 동작
디스패처 서블릿을 통해 요청을 처리할 컨트롤러를 찾는다.
컨트롤러에게 작업을 건내주고 결과물을 받아온다.
아래 그림을 보면서 동작 순서를 조금 더 자세히 알아보자.
- Request를 DispatcherServlet이 받는다.
- Request 정보를 가지고 적절한 Controller를 찾는다.
- Request을 Controller로 건내줄 HandlerAdapter를 찾아 건내준다.
- HandlerAdapter가 Controller로 Request를 건내준다.
- 개발자가 만든 로직(비즈니스)를 처리한다.
- 처리된 반환값을 HandlerAdapter에게 건내준다.
- HandlerAdapter는 반환값을 DispatcherServlet에게 건내준다.
- 반환값(Response)을 응답한다.
동작 순서를 보다보니 DispatcherServlet말고 다른 객체들이 등장했다.
HandlerMapping는 적절한 Controller를 찾는다.
HandlerAdapter는 Controller에게 Request를 건내준다.
아.. 그렇구나.. 라는 생각이 들어서 RestController를 기준으로 조금 더 자세한 그림을 그려봤다.
이 그림을 통해서 동작을 조금만 더 보려고 한다.
아래는 DispatcherServlet의 doDispatch() 메서드이다.
doDispatch()의 메서드 내부를 보면 크게 몇 가지 볼 수 있다.
- getHandler() : 클라이언트 요청에 맞는 HandlerMapping을 선택하여 HandlerExecutionChain을 가져온다.
- getHandlerAdapter() : HandlerExecutionChain에 맞는 HandlerAdapter를 가져온다.
- ha.handle() : HandlerAdapter를 실행한다. (컨트롤러 메서드를 실행한다)
🟢 01. HandlerMapping
클라이언트의 요청에 맞는 HandlerMapping을 찾아서 실행한다.
이 때 HandlerMapping에서 HandlerExecutionChain을 반환하게 된다.
🟢 02. HandlerAdapter
HandlerExecutionChain에는 요청에 맞는 핸들러가 저장되어 있다.
HandlerAdapter를 가져오기 위해서는 HandlerExecutionChain에 있는 핸들러를 보고 판단한다.
HandlerAdapter도 마찬가지로 받아온 핸들러(handler)를 지원하는 HandlerAdapter를 찾아 반환한다.
🟢 03. HandlerAdapter.handle()
처리해줄 HandlerAdatper를 찾았다면 handle()를 호출해서 작업을 진행하게 된다.
이 때 ha가 HandlerAdapter의 자식 클래스인 RequestMappingHandlerAdapter라고 생각하고 진행하겠다.
handle() 메서드를 실행하면 handleInternal() 메서드를 호출한다.
handle() 메서드의 세 번째 인자로 넘겨준 HandlerExecutionChain을 HandlerMethod로 형변환한 것을 볼 수 있다.
🟢 04. RequestMappingHandlerAdapter.handleInternal()
현재 클래스는 RequestMappingHandlerAdapter이다.
hanldeInternal() 메서드에 들어가면 invokeHandlerMethod() 메서드를 호출하게 된다.
이 invokeHandlerMethod() 안에서 ArgumentResolver와 ReturnValueHandler의 동작을 볼 수 있다.
🟢 05. RequestMappingHandlerAdapter.invokeHandlerMethod()
ServletInvocableHandlerMethod 객체를 생성하고 ArgumentResolver들과 ReturnValueHandlers들을 세팅한다.
ServletInvocableHandlerMethod의 invokeAndHandle() 호출하면
컨트롤러의 메서드 인자값을 ArgumentResolver를 통해 얻고
컨트롤러의 메서드를 실행하여 반환값을 ReturnValueHandler를 통해 얻게 된다.
🟢 06. ServletInvocableHandlerMethod.invokeAndHandle()
RequestMappingHandlerAdpater에서는 요청에 대한 메서드를 찾아 실행하고 반환 받은 값을 리턴한다.
- InvocableHandlerMethod.invokeForRequest()
- 메서드의 인자 값을 해결하고 주어진 요청의 메서드를 호출한다.
- HandlerMethodReturnValueHandler.handleReturnValue()
- 메서드 반환 타입에 맞게 형변환하여 응답한다.
🟢 07. HandlerMethodReturnValueHandler.handleReturnValue()
인자로 받아온 반환값(returnValue), 반환타입(returnType)에 맞는 ReturnValueHandler를 찾는다.
찾은 ReturnValueHandler의 handleReturnValue() 메서드를 호출한다.
찾은 ReturnValueHandler가 RequestResponseBodyMethodProcessor라고 가정하자.
RequestResponseBodyMethodProcessor의 handleReturnValue를 호출하면 실제로 응답 로직이 진행된다.
👊 정리하자면
클라이언트의 요청이 들어왔을 때 어떤 식으로 처리되는지 알아봤다.
- HandlerMapping을 통해서 핸들러(컨트롤러)를 찾는다.
- 찾은 핸들러(컨트롤러)를 통해서 HandlerAdapter를 찾는다.
- HandlerAdapter를 통해서 실제 컨트롤러 메서드를 실행하게 된다.
- 메서드의 인자 값을 처리 하기 위해 ArgumentResolver를 이용한다.
- 메서드를 실행하고 반환된 값을 응답하기 위해 ReturnValueHandler를 이용한다.
위 내용에서 생략된 부분이 매우 많다.
그리고 잘못된 내용도 있을 수 있다. (말씀해주시면 수정하겠습니다 !)
이번 포스팅을 통해 "저런 식으로 진행되는구나" 정도의 느낌만 받으면 좋을거 같다.
'🍃 스프링' 카테고리의 다른 글
[Spring] 필터와 인터셉터의 차이 (Filter, Interceptor) (0) | 2023.05.07 |
---|---|
[Spring] 필터(Filter)란 뭘까? (0) | 2023.05.07 |
[Spring MVC - Exception] @ExceptionHandler와 ExceptionHandlerExceptionResolver로 예외 처리하기 (1/2) (0) | 2023.04.17 |
[Spring MVC - ArgumentResolver] ArgumentResolver를 이용해서 컨트롤러 메서드의 파라미터 받기 (6) | 2023.04.13 |