[cs - Spring] Dispatcher Servlet 원리

링딩·2023년 4월 27일
0

Computer Science

목록 보기
41/49




스프링 MVC 전체 구조

오늘 우리는 이 중에서 Dispatcher Servlet에 대해서 좀 더 배워보자.

Dispatcher Servlet


1. 개념

◽ Dispatcher-Servlet(디스패처 서블릿) 이란?

디스패처 서블릿의 dispatch는 "보내다"라는 뜻을 가진다. 곧 디스패처 서블릿은 HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러(Front Controller)라고 정의한다.


더 자세히 풀면...🤔


클라이언트로부터 어떠한 요청이 오면...
ex)Tomcat(톰캣)과 같은 '서블릿 컨테이너'가 요청을 받는다.
그리고 이 모든 요청을 프론트 컨트롤러인 '디스패처 서블릿'이 가장 먼저 받게 된다.
그리고 이 '디스패처 서블릿'공통적인 작업을 먼저 처리를 한 후, 해당 요청을 처리해야 하는 '컨트롤러'를 찾아서 작업을 위임 한다.



+) Front Controller (프론트 컨트롤러)???

주로 '서블릿 컨테이너' 의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서 처리해주는 컨트롤러로써, MVC 구조에서 함께 사용되는 디자인 패턴이다.



2. Disptcher-Servlet(디스패처 서블릿)의 장점

과거에는 모든 서블릿을 URL 매핑을 위해 web.xml에 모두 등록해주어야 했다.. 🤔

그.러.나 '디스패쳐 서블릿'이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리하면서 상당히 편리하게 이용할 수 있게 되었다✌✌

즉, 우리는 컨트롤러를 구현해두기만 하면 디스패처 서블릿가 알아서 적합한 컨트롤러로 위임을 해주는 구조가 되었다.


물론 장점만 있지는 않다.

2. Dispatcher-Servlet의 단점도 있었다.

◽ 문제상황

모든 요청을 처리하다보니 이미지나 HTML/CSS/JavaScript 등과 같은 정적 파일에 대한 요청마저 모두 가로채버려서
-> 정적자원을 불러오지 못하는 상황이 발생되었었다.



그로인해 개발자들은 2가지 방법을 고안했는데...

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

  • 첫번째 방법은 클라이언트의 요청을 2가지로 분리해서 구분하는 것
    -> but, 코드가 지저분 함, 요청에 따라서 url로 구분을 지어줘야 하므로 직관적 설계를 벗어남

2. 애플리케이션 요청을 탐색하고 없으면 정적 자원 요청으로 처리 [현재]

  • Dispatcher Servlet이 요청을 처리할 컨트롤러를 먼저 찾는다. 이때 컨트롤러를 찾지 못한 경우 2차적으로 설정된 자원경로를 탐색해 자원 탐색을 한다.
    => 리소스 관리를 효율적으로 할 수 있다.
    => 확장이 용이하다.






3. Dispatcher-Servlet(디스패처 서블릿)의 동작 과정

우리는 앞에서 정의하고 기능을 자세히 들여다 보면서 알게 되었다 싶이 이 곳에서의 주 일은

  • 디스패처 서블릿은 적합한 컨트롤러와 메소드를 찾아 요청을 위임 해주는 것이다.

◽ Dispatcher Servlet의 동작과정

  1. 클라이언트의 요청을 디스패처 서블릿이 받음
  2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾음
  3. 요청을 컨트롤러로 위임할 핸들러 어댑터를 찾아서 전달함
  4. 핸들러 어댑터가 컨트롤러로 요청을 위임함
  5. 비지니스 로직을 처리함
  6. 컨트롤러가 반환값을 반환함
  7. 핸들러 어댑터가 반환값을 처리함
  8. 서버의 응답을 클라이언트로 반환함

🌈 디스패처 서블릿을 통해서 요청을 처리할 컨트롤러를 찾아서 위임하고, 그 결과를 받아오는 것을 하는구나!!🙌



3-1. 클라이언트의 요청을 디스패처 서블릿이 받음

디스패처 서블릿은 가장 먼저 요청을 받는 프론트 컨트롤러입니다.

  • 서블릿 컨텍스트(Web Context)에서 필터들을 지나 '스프링 컨텍스트'에서 Dispatcher Servlet
    이 가장 먼저 요청을 받게 된다



3-2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾음

  • '디스패처 서블릿'은 요청 정보를 바탕으로, 요청을 처리할 컨트롤러를 찾고 해당 메소드를 호출해야 한다.
  • 요청을 처리할 컨트롤러는 주로 HandlerMapping의 구현체 중 하나인 RequestMappingHandlerMapping가 찾아준다.

이때 요청을 처리할 대상은 컨트롤러가 아닌 컨트롤러를 가지고 있는 HandlerMethod 객체이다.
-> HandlerMethod를 갖는 이유는 컨트롤러와 컨트롤러의 메소드 등을 포함해 부가적인 정보들이 더욱 필요하기 때문

그리고 이렇게 찾아온 HandlerMethodHandlerMethodExecutionChain으로 감싸서 반환한다.
-> why? 컨트롤러로 요청을 넘겨주기 전에 처리해야 하는 인터셉터 등을 포함하기 위해



3-3. 요청을 컨트롤러로 위임할 '핸들러 어댑터'를 찾아서 전달

사실 요청을 직접 위임하진 않고 중간 다리인 '핸들러 어댑터(HandlerAdapter)'를 통해 어댑터 패턴 을 적용하여 컨트롤러로 위임하는 것이다.

  • 왜 어댑터 패턴?
    개발자로 인해 다양하게 작성되는 컨트롤러에 대응하고자 어댑터 패턴을 적용해 컨트롤러의 구현 방식에 규제 받지 않고 요청을 위임하고자 함.



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

  • '핸들러 어댑터'가 컨트롤러로 요청을 넘기기 '공통적인 전처리 과정' 이 필요 하다.

어떻게 보면 핸들러 어댑터라는 집사를 부르는거 같기도 하다. 직접 일은 하지 않고 남을 시켜서 부른다니🤔

요청에 매칭되는 인터셉터들도 실행을 시키고, @RequestParam, @RequestBody 등으로 파라미터를 준비하는 ArgumentResolver도 실행하는 등의 다양한 공통 작업들이 수행된다.
-> 이러한 전처리 작업들이 완료되면 파라미터 값들과 함께 컨트롤러로 요청을 위임한다.


3-5. 비지니스 로직을 처리함


3-6. 컨트롤러가 반환값을 반환함

  • 비지니스 로직이 처리된 후에는 컨트롤러가 반환값을 반환한다.

    응답 데이터를 사용하는 경우에는 주로 ResponseEntity를 반환하게 되고, 응답 페이지를 보여주는 경우라면 String으로 View의 이름을 반환할 수도 있다.


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

  • '핸들러 어댑터'는 컨트롤러로부터 받은 반환값을 응답 처리기인 ReturnValueHandler가 후처리한 후에 다시 'Dispatcher Servlet'으로 돌려준다.
  • ex 1 ) 만약 컨트롤러가 ResponseEntity를 반환하면 HttpEntityMethodProcessor'MessageConverter'를 사용해 응답 객체를 직렬화하고 응답 상태(HttpStatus)를 설정한다.

  • ex 2) 만약 컨트롤러가 View 이름을 반환하면 View를 반환하기 위한 준비 작업을 처리


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

  • 'Dispatcher Servlet'을 통해 반환되는 응답은 다시 필터들을 거쳐 클라이언트에게 반환된다.

이때 ex 1) 응답이 데이터라면?
=> 그대로 반환
ex 2 ) 응답이 화면이라면 View의 이름에 맞는 View를 찾아서 반환해주는 ViewResolver가 적절한 화면을 내려줍니다.




출처

망나니 개발자님의 글을 읽고 작성하였습니다.

profile
초짜 백엔드 개린이

0개의 댓글