Servlet
클라이언트의 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 기술
- servlet은 JAVA EE의 표준 중 하나로, javax.servlet Package를 기반으로 Server에서 동작하는 Class들을 의미한다.
- 각 Servlet은 init(), service(), destroy() 3개의 method를 반드시 정의해야 한다.
init()
: init()은 Servlet 생성시 호출된다. Parameter로 javax.servlet.ServletConfig Interface 기반의 Instance가 넘어오는데, Servlet을 초기화 하고 Servlet이 이용하는 자원을 할당하는 동작을 수행한다.service()
: Servlet으로 요청이 전달될 때마다 호출된다. 실제 Service Logic을 수행한다.destroy()
: Servlet이 삭제될 때 호출된다. Servlet에서 이용하는 자원을 해지하는 동작을 수행한다.
→ 웹서버의 측면에서 서블릿을 바라보면
1) Socket의 생성
2) input/OutputStream의 생성등의 업무를 개발자를 대신해서 진행해준다.- Container는 Servlet의 생성주기(life-cycle)을 관리하고, 매번 요청이 들어올 때 마다 새로운 쓰레드를 요청별로 부여한다.
즉,The Container runs multiple threads to process multiple requests to a single servlet (in one process).
이다.
놓치기 쉬운 개념
- 하나의 클라이언트에 하나의 쓰레드가 부여되는 것 아닌가? 각각의 클라이언트는 자신만의 쓰레드에서 동작하는데요?
- A: 요청당 하나의 쓰레드다. container는 누가 요청을 보냈는지에 대해서는 관심이 없다. 새로운 요청은 새로운 쓰레드를 만들어낸다.
- Thread-per-request를 Thread-per-connection에 우선해서 쓰는 이유는 뭐죠?
- A: Scalability에 유리하다. Java 쓰레드는 비용이 비싼데, 1Mb 메모리 segment가 하나씩 붙는다. active 상태이건 idle 상태이건 상관이 없다. 커넥션 하나당 하나의 쓰레드에 붙이면, 쓰레드는 요청이 계속 오기까지 idle 상태로 대기를 타야할 것이다. 궁극적으로 framework가 새로운 커넥션을 만들지 못하게 될 것이고 (쓰레드를 더 만들 수가 없어서)… 아니면 기존 커넥션을 끊어버리든가 해야겠죠.. 즉, 커넥션이 연결되는 동안 스레드가 유지되어야 합니다. 그런데 thread-per-request를 쓰면 request가 진행될 때만 쓰레드가 개입을 하니까, 서비스는 수만명이 사용한다고 하더라도 현재 사용중인 요청에만 쓰레드를 투입시키면 되니까 경제적이다 이겁니다.
다만, 클라이언트가 지속적으로 요청을 날려야 하는 상황에서는 HTTP Keep-alives를 사용하여 Connection 별로 Thread를 지속적으로 유지하도록 할 수 있습니다.
ServletContainer
servletContainer
(Web container)는 servlet Instance를 생성하고 관리하는 역할을 수행한다.
우리가 대표적으로 알고 있는ServletContainer
는Tomcat
이다.
ServletContainer는 하나의 WebApplication에 하나씩 붙는다. servletContainer인 tomcat도 자바프로그램이기 때문에 하나의 JVM이 붙는다. 즉1-WAS per 1-JVM
servlet
과 servletConfig
인터페이스를 구현해 제공되는데, GenericServlet 추상클래스가 위 두 인터페이스의 추상 메서드를 구현하고 HttpServlet이 GenericServlet을 상속받는다. 여기서 doGet, doPost 메서드가 나온다.결국, 개발자가 작성한 비지니스로직도 ServletContainer가 관리하게 되고, Spring MVC도 ServletContainer가 관리하고 있는 Servlet 한개를 의미한다.
SpringMVC로 들어가는 모든 요청&응답은 DispatcherServlet이 관리하고 있는 것이다.
- Servlet container는 process하나에 배정돼있고, 이에 따르는 요청들은 Thread 별로 처리하도록 ThreadPool에서 역할을 배정시킨다.
그 중, 클라이언트가 임의의 서블릿을 실행하라고 요청했는데, 최초의 요청이면init()
을 실행하고,
최초가 아니라면 새로 서블릿을 만들지 않고 메서드영역에 있는 서블릿을 참고해서service()
를 실행하는 것이다.
이렇게 개발자가 아닌 프로그램에 의해 객체들이 관리되는 것을IoC(Inversion of Control)
이라 한다.
- Spring Web MVC가 없던 과거에는, URL마다 Servlet를 생성하고
Web.xml
로 Servlet로 관리했다. URL마다 서블릿이 하나씩 필요하다 보니, 매번 서블릿 인스턴스를 만들어야 했다.
그런데Dispatcher Servlet
이 도입된 이후에는FrontController 패턴
을 활용할 수 있게 되면서 매번 서블릿 인스턴스를 만들 필요가 없어졌다. 또한, View를 강제로 분리하는 효과도 볼 수 있게 되었다.
출처