2022.01.21
일반적으로 웹 서버는 정적인 페이지만을 제공한다. 그렇기 때문에 상품 검색, 댓글 작성과 같은 사용자의 요청을 완료한 동적인 페이지를 제공하기 위해서는 동적인 처리를 담당할 무언가가 필요했고, 이러한 역할을 담당하는 CGI
가 등장하게 되었다.
CGI는 웹 서버와 응용 프로그램간에 데이터를 주고받기 위한 방법이나 규약을 뜻한다. CGI 방식은 어떠한 프로그래밍 언어로도 구현이 가능하다.
CGI는 멀티 프로세스
방식을 사용하기 때문에 요청이 들어 올 때마다 프로세스를 새로 생성하고, 따라서 상당히 많은 자원을 차지하게 된다.
이를 해결하기 위해서 프로세스가 아닌 스레드
를 생성하는 Servlet
이 등장했다.
Servlet은 클라이언트의 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 기술 을 말한다. 간단히 말해서, 웹 서버 프로그래밍을 위해 만들어진 자바 프로그램 혹은 코드라고 할 수 있다.
위에서 CGI의 멀티 프로세스 방식을 멀티 스레드 방식으로 확장한 것이 Servlet 이라고 했다. 따라서 CGI가 요청을 받아 처리한 결과를 동적으로 응답해주는 역할을 하는 것처럼 Servlet도 동일한 역할을 수행한다.
Servlet도 인터페이스이므로 구현체가 존재한다. Spring MVC
는 웹 애플리케이션을 만드는데 특화된 서블릿 구현체이다. Spring MVC 에서는 Dispatcher Servlet
이라는 모든 요청을 담당하는 서블릿을 두고 컨트롤러에 위임하여 요청을 처리한다.
Servlet Container
에 의해 관리 및 실행된다.클라이언트가 요청을 보내면 Servlet Container가 요청을 받는다. 이때 제일 앞에서 서버로 들어오는 모든 요청을 처리하는 Front Controller 라는 것을 Spring에서 정의하였고, 이를 Dispatcher Servlet
이라고 한다.
이와같은 프론트 컨트롤러 디자인 패턴이 적용된 Spring MVC를 통해 개발자는 별도의 서블릿 개발 없이 Controller의 구현만으로 동적인 응답을 클라이언트에게 줄 수 있다.
HandlerMapping
HandlerAdapter
ViewResolver
서블릿을 관리해주는 컨테이너 이다. 서블릿 컨테이너는 클라이언트 요청을 받고 응답할 수 있도록 웹 서버와 소켓으로 통신하며 대표적으로 톰캣이 있다. 톰캣은 웹 서버와 통신하여 JSP와 Servlet이 작동하는 환경을 제공해준다.
웹 서버와 통신 지원
서블릿과 웹 서버가 쉽게 통신할 수 있도록 해준다. 일반적으로 소켓을 만들고 listen, accept 등의 일련의 통신 과정이 필요하지만, 서블릿 컨테이너는 이러한 기능을 API로 제공하여 복잡한 과정을 생략할 수 있게 해준다. 그래서 개밸자가 서블릿에 구현해야 하 비지니스 로직에만 초점을 둘 수 있도록 도와준다.
서블릿 생명주기 관리
서블릿 클래스를 로딩해서 인스턴스화하고, 초기화 메서드를 호출하고, 요청이 들어오면 적합한 스블릿 메소드를 찾아서 호출한다.
서블릿의 생명이 끝나는 순간 가비지 컬렉션을 진행한다.
멀티스레딩 지원 및 관리
서블릿 컨테이너는 요청이 올 때마다 새로운 자바 스레드를 생성하여 작업을 수행한다. 여러 요청이 동시에 들어오면 멀티 스레드 환경으로 작업을 한다.
서블릿 로딩
웹 서버가 시작되면 서블릿 컨테이너가 모든 서블릿을 배포하고 로드한다.
서블릿 인스턴스 생성
모든 서블릿 클래스가 로드되면 서블릿 컨테이너는 각 서블릿 클래스의 인스턴스를 생성한다. 서블릿 클래스당 한 번만 인스턴스를 생성하고 서블릿에 대한 모든 요청은 동일한 서블릿 인스턴스에서 실행된다.
init() 메서드 한 번 호출
모든 서블릿 클래스가 인스턴스화 되면 인스턴스화된 각 서블릿에 대해 init() 메소드가 호출되고, 서블릿을 초기화한다.
클라이언트 요청에 대하여 반복적으로 service() 메서드 호출
웹 서버는 서블릿에 대한 요청을 수신할 때마다 service() 메소드를 호출하는 새 스레드를 생성한다. 서블릿이 GenericServlet이면 요청은 service() 메소드 자체에 의해 제공되고, 서블릿이 HttpServlet이면 service() 메소드는 요청을 수신하고 요청 유형에 따라 올바른 핸들러 메소드에 전달한다.
destory() 메서드 호출
서블릿 컨테이너가 종료되면(일반적으로 웹 서버를 중지할 때 발생) 모든 서블릿을 언로드하고 destroy() 메소드를 호출한다.
위의 내용을 바탕으로 Web에서 클라이언트가 Request를 보내고 Response를 받는 과정을 정리해보자.
Tomcat을 실행하면 로그를 통해 서비스를 위해 어떤 순서로 프로젝트 세팅이 이루어지는지 확인할 수 있다.