뜌릅

Dispatcher Servlet이 뭔가요 본문

SPRING

Dispatcher Servlet이 뭔가요

TwoCastle9 2023. 6. 21. 16:03
반응형

Servlet


서블릿이란, 자바를 사용해서 웹을 만들기 위해 필요한 기술입니다. 클라이언트의 요청에 따른 결과를 다시 전송해야 하는데, 이러한 역할을 해주는 자바 프로그램입니다.

Sevlet의 특징

  • 클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트
  • html을 사용하여 요청에 응답한다.
  • Java Thread을 이용하여 동작한다.
  • MVC패턴에서 Controller로 이용됩니다. 정확히는 @Controller어노테이션을 붙이게 되면, 스프링 부트 내부에서 사용하는 Dispatcher Servlet이 클라이언트 요청을 받아 적절한 컨트롤러로 라우팅하는 역할을 합니다.
  • jakarta(javax).servlet.http.HttpServlet 클래스를 상속받습니다.

동적인 페이지를 제공하기 위해 웹서버(Apache)는 다른 곳(WAS, Tomcat)에 도움을 요청하여 동적인 페이지를 작성해야 합니다. 동적인 페이지로는 임의의 이미지만을 보여주는 페이지와 같이 사용자가 요청한 시점에 페이지를 생성해서 전달해 주는 것을 의미합니다. 여기서 웹서버가 동적인 페이지를 제공할 수 있도록 도와주는 어플리케이션이 서블릿이며, 이런 어플리케이션들을 통틀어 CGI(Common Gateway Interface)라고 합니다.

Servlet의 동작 방식(MVC구조)

  1. 사용자(클라이언트)가 요청을 함. (HTTP라고 가정함) HTTP request가 웹서버에 도착(밑의 그림에는 생략되어있음)
  2. 웹서버는 Servlet Container에게 전달함.
  3. 요청을 받은 Servlet Container는 HttpServletRequest, HttpServletResponse 객체를 생성함.
  4. Web.xml 기반으로 사용자가 요청한 URL이 어느 서블릿에 대한 요청인지 찾기.
  5. 해당 서블릿에서 service 메소드를 호출한 후에 클라이언트의 Get, Post여부에 따라 doGet() or doPost()을 호출함.
  6. 응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킴.

참고로 정적인 페이지에 대해서는 Servlet가 아닌 앞에있는 Web Server에서 자원을 반환해줍니다.

  • 참고로 REST API로 스프링을 구성할 경우 동적 페이지 구성보다는 라우팅이 주요 기능이라고 보면 됩니다.

 

Servlet Container의 역할


쉽게 말해 서블릿을 관리해주는 컨테이너로, 클라이언트의 요청을 받아주고 응답을 할 수 있게, 웹서버와 소켓으로 통신하는 녀석입니다. 대표적인 예로 톰캣이 있습니다. 톰캣은 웹서버와 통신하며 Servlet이 작동하는 환경을 제공해줍니다. 또한 서블릿의 생명주기를 관리하고, 멀티쓰레드 지원 및 관리 등의 역할을 한다고 합니다.

서블릿의 생성주기는 HikariCP처럼 Pooling방식(적어도 톰캣은 자바 쓰레드를 풀링으로 관리한다고 합니다.)을 이용합니다. 그 이유는 쓰레드의 생성과 삭제의 비용이 크기 때문입니다.

Dispatcher Servlet


Dispatch는 “보내다”라는 뜻을 가지고 있습니다. Dispatcher 서블릿은 Http 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 Front 컨트롤러라고 정의할 수 있습니다.

보다 자세히 설명하자면, 클라이언트로부터 요청이 들어오면, 서블릿 컨테이너(톰캣 내부에 존재)가 요청을 받게 됩니다. 그리고 이 모든 요청을 서블릿 컨테이너의 디스패처 서블릿이 가장 먼저 받게 됩니다. 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에 해당 요청을 처리해야하는 컨트롤러를 찾아 작업을 위임합니다.

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

Dispatcher-Servlet의 장점

위의 web.xml을 이용해서 url맵핑을 하던것과는 달리 Dispatcher-Servlet은 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리하면서 상당히 편리하게 이용할 수 있게 되었습니다. 우리는 컨트롤러를 구현해두기만 하면 Dispatcher Servlet이 알아서 적합한 컨트롤러로 위임을 해주는 구조가 되었습니다.(위임(Delegate)라는 키워드를 유심히 봅시다.)

정적 자원의 처리

위에서 웹서버가 서블릿의 정적 자원을 처리해준다고 했지만, Dispatcher-Servlet은 정적자원까지도 처리해 줍니다. 하지만 모든 요청을 처리하다 보니 이미지, HTML파일 등등 정적 파일에 대한 정적자원을 불러오지 못하는 상황도 발생하곤 했습니다. 이를 위해 2가지 방법을 고안했습니다.

  1. 정적 자원 요청과 애플리케이션 요청을 분리
  2. 애플리케이션 요청을 탐색하고 없으면 정적 자원 요청으로 처리

1번 방법은 /apps의 URL로 접근시 동적 요청으로, /resource의 URL로 접근하면 정적요청으로 분리하는 방법입니다. 방식은 직관적이나, 코드가 더러워지고 모든 요청에 저런 URL을 붙여줘야 하므로 직관적인 설계가 될수 없습니다.

2번 방법은 요청에 대한 컨트롤러를 찾을 수 없는 경우에 2차적으로 설정된 자원 경로를 탐색하는 것입니다. 영역 분리가 되므로 효율적인 리소스관리와 확장을 용이하게 해준다는 장점이 있습니다.

Dispatcher-Servlet의 동작과정

서블릿 컨테이너 내부에 존재합니다.

 
  1. 클라이언트의 요청을 디스패처 서블릿이 받음
  2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾음. (맵핑 정보만을 찾습니다.)
  3. 해당 맵핑 정보와 요청에 대한 정보를 Adapter에게 넘겨 줍니다.
  4. Adapter는 맵핑정보를 통해 개발자가 구현한 컨트롤러(프레젠테이션 레이어)에 요청을 위임시킵니다.
  5. 서비스를 호출합니다.
  6. 개발자가 구현한 컨트롤러에서 리턴값을 반환합니다.
  7. Adapter가 반환값을 처리하여 서블릿에 반환해줍니다.
  8. 서블릿은 이 정보를 다시 클라이언트에 반환합니다.
 
Web Context == Servlet Context

위의 내용을 좀 더 스프링부트 관점에서 자세히 풀어 써보자면,

스프링부트가 실행하게 되면 아래의 그림처럼 서블릿부터 생성하게 됩니다.

스프링 부트의 모듈이 실행한후 Servlet을 생성합니다.

refresh()함수를 호출하여, 기존의 정보를 날린후 새로이 웹서버를 생성시킵니다.

 

잘보면 ServletWebSererFactory의 AutoConfiguration에 따라 DispatcherServlet의 생성자도 호출되었습니다.

이렇게 위와 같이 기본 Dispatcher Servlet을 빈 생성자로 생성시킵니다.

그리고 생성되었던 서블릿은 다시 위의 CreateWebServer()로 돌아와서 만들어진 톰캣 객체에다가 넣어 주고 있습니다.

헬스체크가 돌때도 서블릿의 doService가 돌게 됩니다. health Check 또한 헬스체커(클라이언트가) manage/health의 url로 servlet에 요청을 보내기 때문입니다.



디스패처 서블릿은 가장 먼저 요청을 받는 서블릿입니다. 서블릿 컨텍스트(웹 컨텍스트)에서 필터들을 지나서 스프링 컨텍스트 내부의 Dispatcher-Servlet이 가장 먼저 요청을 받게 됩니다. 디스패처는 요청을 처리할 핸들러를 찾고 해당 객체의 메소드를 호출합니다. 해당 역할을 하는것이 Handler Mapping함수입니다.

그런데 생각해보면 Rest API의 경우 @RequestMapping과 GetMapping을 통해서, GQL의 경우 @QueryMapping을 통해서 컨트롤러를 작성합니다. 이러한 다양한 스펙에 대응하기위해 HandlerMapping는 인터페이스로 공통적인 스펙만을 정의하고, 다양한 구현 방법에 따라 요청을 처리할 대상을 찾도록 되어 있습니다.

반응형

'SPRING' 카테고리의 다른 글

Audit Logging Column이 생성되지 않는 경우 (키중복 save)  (0) 2023.06.21
부하테스트  (0) 2023.06.21
Soft Delete는 언제 사용하고, 어떻게 사용하나요??  (0) 2023.06.21
HikariCP  (0) 2023.06.21
JPA, JDBC: Java의 API들  (0) 2023.06.21