[ Spring ] Dispatcher-Servlet

5tr1ker·2023년 5월 9일
0

Spring

목록 보기
5/10
post-thumbnail

Dispatcher-Servlet 의 개념

Dispatcher는 "보내다" 라는 뜻을 가지고 있습니다. 따라서 Dispatcher-Servlet은 HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적절한 컨트롤러에게 전달해주는 프론트 컨트롤러 입니다.
자세하게 설명하자면 , 클라이언트로부터 요청이 들어오면 Tomcat 과 같은 서블릿 컨테이너가 요청을 받게 됩니다. 그리고 이 모든 요청은 프론트 컨트롤러인 디스패처 서블릿이 가장 먼저 받게 되고, 이후에 공통작업을 처리한 후에 적합한 컨트롤러에게 요청을 위임합니다.
여기서 프론트 컨트롤러는 서블릿 컨테이너의 제일 앞에서 서버로 들어오는 요청을 처리해주는 받아서 처리해주는 컨트롤러로 , MVC 구조에서 함께 사용되는 디자인 패턴입니다.

Dispatcher-Servlet 의 장점

Spring MVC 는 Dispatcher-Servlet 이 등장함에 따라 web.xml 에서 해야하는 일을 축소시켜주었습니다. 과거에는 모든 URL 매핑을 web.xml 에서 설정해주어야 하지만, dispatcher-servler 이 등장하면서 모든 요청을 핸들링해주고 공통 작업을 처리해주면서 편리하게 이용할 수 있게 되었습니다. 우리는 컨트롤러만 구현해주면 Dispatcher-Servlet이 적절한 컨트롤러로 위임해주는 구조가 되었습니다.

정적 자원의 처리

Dispatcher-Servlet 이 요청을 Controller 에게 넘겨주는 방식은 효율적으로 보이지만, 모든 요청을 처리하다보니 정적 자원에 대한 요청도 가로채기 때문에 정적 자원을 불러오지 못하는 상황이 발생합니다. 이를 해결하기위해 2가지 방법을 고안합니다.

정적 자원 요청과 애플리케이션 요청을 분리

  • /app 의 URL로 접근하면 애플리케이션 요청 ( Dispatcher-Servlet이 당담 )
  • /resource 로 접근하면 정적 자원 요청 ( Dispatcher-Servlet이 담당하지 않음 )

이러한 방식은 코드가 지저분해지며, 추가적인 URL 이 붙기 때문에 직관적인 설계과 될 수 없습니다.

애플리케이션 요청을 탐색하고 없으면 정적 자원 요청

먼저 요청을 위임할 컨트롤러를 탐색하고, 요청을 처리할 컨트롤러가 없다면 정적 자원에 대한 경로를 탐색하는 방법입니다. 이렇게 하면 효율적인 리소스 관리가 되며, 추후에 확장성에 용이하다는 장점이 있습니다.

Dispatcher-Servlet의 동작 과정

1. 클라이언트의 요청을 받음

디스패처 서블릿은 들어오는 요청을 먼저 받는 프론트 컨트롤러입니다. 서블릿 컨텍스트의 필터들을 지나 스프링 컨텍스트의 디스패처 서블릿이 요청을 받게 됩니다.

2. 요청 정보를 위임할 컨트롤러 탐색

디스패처 서블릿은 받은 요청을 처리할 컨트롤러를 찾고 HandlerMethod를 호출합니다.

요청을 처리할 컨트롤러는 HandlerMapping의 구현체 중 하나인 RequestMappingHandlerMapping 이 찾아줍니다. 해당 객체는 내부에 HashMap으로 관리하고 있어서 요청 정보를 Key로 사용하여 요청을 처리할 대상을 찾습니다. 이때 요청을 처리할 대상은 컨트롤러가 아닌 컨트롤러를 가지고 있는 HandlerMethod 객체입니다. HandlerMethod 를 반환하는 이유는 컨트롤러에 대한 부가적인 정보가 필요하기 때문입니다.

그리고 찾은 HandlerMethod 를 HandlerMethodExecutionChain으로 감싸서 반환하는데, 그 이유는 컨트롤러로 요청을 넘겨주기전에 전처리를 해야하는 인터셉터를 포함하기 위함입니다.

3. 요청을 컨트롤러로 위임할 핸들러 어댑터를 탐색

디스패처 서블릿은 요청을 직접 컨트롤러에 위임하는 것이 아니라 HandlerAdapter 를 통해 컨트롤러로 요청을 위임합니다. 이때 HandlerAdapter 로 컨트롤러를 호출하는 이유는 컨트롤러의 구현 방식이 다양하기 때문입니다. 그래서 다양하게 작성되는 컨트롤러를 대응하기 위해 HandlerAdapter 라는 어댑터 패턴을 통해 컨트롤러의 구현 방식에 상관없이 요청을 위임할 수 있게 했습니다.

컨트롤러 구현 방식은 Controller 인터페이스와 어노테이션 기반의 컨트롤러가 있습니다.

4. 핸들러 어댑터가 컨트롤러로 요청을 위임

핸들러 어댑터가 컨트롤러를 호출하기 전에 공통적인 전처리 작업을 수행합니다. 요청에 매핑되는 인터셉터를 실행시키고, @RequestBody 와 @RequestParam 등 파라미터 값들을 준비하는 ArgumentResolver 도 실행하는 등의 공통된 작업을 수행합니다. 이러한 전처리 작업이 완료되면 파라미터에 값을 넣어 컨트롤러에 요청을 위임합니다.

5. 비즈니스 로직 처리

이후의 컨트롤러는 서비스를 호출하고 비즈니스 로직을 수행합니다.

6. 컨트롤러가 값을 반환

비즈니스 로직이 처리된 후 컨트롤러는 결과값을 반환합니다. 응답 데이터를 사용하는 경우에 ResponseEntity를 반환하고, 응답 페이지는 view의 이름을 반환합니다.

7. 핸들러 어댑터가 반환값을 처리

핸들러 어댑터는 컨트롤러로 부터 받은 반환값을 ReturnValueHandler 를 통해 후처리를 한 후 디스패처 서블릿으로 돌려줍니다.

만약 컨트롤러가 ResponseEntity를 반환했다면 MessageConverter 를 사용해 응답 객체를 직렬화 하고 응답 상태를 설정합니다. 만약 컨트롤러가 view의 이름을 반환했다면 view를 반환하기 위한 준비 작업을 처리합니다.

8. 서버의 응답을 클라이언트로 반환

디스패처 서블릿을 통해 반환되는 응답을 다시 필터를 거쳐 클라이언트에게 반환됩니다. 이때 응답이 데이터라면 그대로 반환되지만, 반환 타입이 view 라면 ViewResolver 를 통해 적절한 화면을 반환합니다.

참고

참고 블로그 1 : https://mangkyu.tistory.com/18

profile
https://github.com/5tr1ker

0개의 댓글