(추가 참고 - 지금 내가 만든 서블릿의 service 함수는 로그만 출력하게 두었지만, HttpServlet의 service 함수는 HTTP 메서드에 따라 실행되는 비즈니스 로직이 다 다르다. - 자세한 내용은 HttpServlet 클래스의 service 함수를 확인해보면 알게 된다.)
.
실행 로그를 확인해보면 init 로그는 한번 service 로그는 세 번이 출력된 것을 알 수 있는데, 이는 서블릿 컨테이너 알아볼 때 다루기로 하자.
서블릿도 생성해보고 동작도 해봤는데 대체 서블릿은 어떻게 클라이언트의 요청을 받을 수 있는 것일까?
그건 바로 서블릿 컨테이너를 통해 진행된다.
서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료하는 서블릿의 생명 주기를 관리하며, 클라이언트에서 요청이 들어왔을 때 컨테이너는 HttpServletRequest, HttpServletResponse 두 객체를 생성하고 동적인 페이지를 생성하여 응답한다.
서블릿 컨테이너가 지원하는 기능
1. 서블릿 생명주기 관리
서블릿 객체는 싱글톤으로 관리한다. (따라서 서블릿을 생성할 때 멤버 변수를 사용할 때 주의해야 한다.)
✔️ init() - 초기화
서블릿이 처음으로 요청될 때 초기화가 한번 진행되며, 초기화된 서블릿은 싱글톤으로 관리된다.
(* 싱글톤으로 관리되기 때문에 서블릿 생성할 때 멤버 변수를 사용할 때 주의해야 한다!)
따라서, 다음에 같은 서블릿이 요청되면 초기화가 다시 일어나는 것이 아니라 기존에 있던 서블릿을 호출하게 된다.
-> 그래서 위에 서블릿 생성하고 동작 확인해 봤을 때 init 로그가 한 번만 출력된 것이다.
✔️ service() - 호출
Servlet 인터페이스를 구현한 HttpServlet 클래스의 doGet, doPost와 같은 메서드가 호출된다.
(HTTP Method에 따라서 호출되는 함수가 다르다!)
✔️ distory() - 종료
서블릿 컨테이너는 더 이상 사용되지 않는 서블릿 인스턴스가 삭제되기 전에 destroy를 한번 실행한다.
//javax.servlet.Servlet
public interface Servlet {
public void init(ServletConfig config) throws ServletException; //초기화
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; //호출
public void destroy(); //종료
}
2. 멀티스레딩 관리
서블릿 컨테이너는 새로운 요청이 들어오면 스레드를 생성해서 서블릿을 호출(One Thread Per Request)한다.
☝ 만약 요청마다 스레드를 생성하면 무한대까지 생성할 수 있는데, 그렇게 되면 서버가 죽지 않을까?
그렇지만 이 문제를 해결하기 위해서 스레드 풀(Thread Pool) 이 지원된다.
스레드 풀에 미리 스레드를 생성하고, 요청이 오면 스레드 풀에서 스레드를 빌려서 쓰고 반납하는 과정을 거친다.
(* tomcat 기준, Thread Pool의 Thred의 기본 개수는 200개이다.)
만약 Thread Pool의 제한 개수를 넘어 요청이 들어온다고 하면, 스레드 대기 및 거절할 수 있도록 처리할 수 있다.
(Thread 대기 및 거절에 대한 내용은 나중에 자세하게 확인해보도록 하자.)
3. 통신 지원
4. 보안관리
서블릿 컨테이너 동작 방식
1. 웹 브라우저에서 요청한다.
2. WAS 서버에서 요청 메시지를 기반으로 request, response 객체를 만들어 서블릿 객체를 호출한다.
☝ 이때, 서블릿 컨테이너에 서블릿이 존재하지 않으면 객체를 초기화하며 서블릿이 존재하면 해당 서블릿을 호출한다.