생각해보면 전부터 톰캣, 서블릿 컨테이너, 서블릿 등 개념어는 난무하는데 머리속에서 깔끔하게 정리가 되지 않았다.
스프링을 파고들어가면 결국엔 근본적으로는 무수한 HTTP Request, Response 속에서 이를 자동화(?)해서 처리해주는 것이 서블릿인데 이 개념이 나에겐 꽤나 모호하게 다가왔다.
소프트웨어의 특징이기도 하지만,
실제로 손에 잡히거나 눈으로 가시적으로 명확하게 볼 수 있는 것이 아니거니와 눈으로 확인하는 과정이라 할지라도 디버깅을 해가면서 보는게 전부인지라 아무래도 더 그런 경향이 있던 것 같다.
무엇보다 해당 궁금증을 파고들어가는 계기가 있었는데 그것은 바로
학습 도중 HttpServlet을 상속받아서 servlet을 커스텀할 때 service 메서드만 override하는 이유였다.
무슨 원리가 있길래 해당 메서드만 오버라이드 하면 자동으로 요청과 응답을 보내고 받을 수 있는지가 궁금하였고 동작 원리가 궁금하였다.
하단은 HttpServlet의 Service 메서드이다.
대강 봐도 알겠지만, 조건문으로 분기하여 doGet, doPost, doPatch등 분류하여,
HTTP 요청 메서드가 무엇이냐에 따라서 HttpServlet 내에서 각각의 메서드를 호출한다.
HttpServlet 내 코드
위의 Service 코드를 보면 알겠지만, 조건문에 따라 분기하여 메서드를 호출한다.
Get 요청이면 doGet을, Post 요청이면 doPost를 실행한다.
굉장히 간단하고 직관적이다.
이를 알기 이해하기 위해서는 서블릿 라이프사이클과 서블릿 컨테이너 자체에 대한 이해가 필요하다.
저번주에 들었던 남궁성님 세미나에서도 남궁성님께서 한 이야기지만
지식을 새로이 접하거나 머리 속으로 정리할 때는 사전에 나열되어있는 딱딱한 지식어로
외우는게 아니라 내가 나만의 언어를 창조해서 이해하고 남들에게 설명할 수만 있으면 된다.
이와 같은 관점에서 서블릿을 나만의 언어로 정의해보자면
서블릿이란 결국 웹브라우저와 같은 Client의 Http Request가 들어올 때 정적리소스를 제외한
동적인 요청에 대해서(가령, 로그인된 회원은 비로그인 회원에 비해 다른 페이지를 띄워준다든지, 입력에 따라 출력이 달라진다든지 무수히 많은 예시가 있겠다. ) 내부에서 특정한 로직을 실행한 후 결과값을 Http Response을 보내주는 역할을 하는 것이라고 할 수 있다.
서블릿 컨테이너이자 WAS의 한 종류라고 할 수 있다.
여기서 말하는 WAS란 Web Application Server의 약자로 일반적인 Web-server와는 구별되는 개념이다.
이해하기 쉽게 간단하게 이야기 하자면 Web Server는 일반적인 HTML, CSS, JS 등과 같은 별도의
로직이 존재하지 않는 정적 리소스 파일을 HTTP 요청에 대해서 응답해주는 서버라고 할 수 있고,
그 뒷단에 존재하는 것이 WAS, 즉 서블릿 컨테이너라고 할 수 있다.
웹에서 Http Requet가 들어오면 WAS는 HttpRequest, HttpResponse 객체를 생성한다.
해당 객체들(Request, Response 객체)은 각 Http 요청마다 쓰레드가 할당되며 해당
요청시마다 인스턴스가 생성된다.
이렇게 생성된 Request, Response 인스턴스들을 전달하는 역할을 하는 쓰레드는
서블릿 컨테이너 내의 특정 쓰레드에 하나씩 할당된다.
즉, 이는 특정 사용자A가 특정 Request를 보내게 되면 WAS가 HttpRequest, HttpResponse 객체를
생성한 후 특정 쓰레드에 할당되고, 해당 쓰레드가 위의 객체들을 서블릿에 전달하여
서블릿이 해당 요청을 수행하는 것이라 할 수 있다.
서블릿의 생명주기는 WAS가 종료될때까지 살아있다.
매 요청마다 생성되고, 응답을 보내면 삭제되는 HttpRequest, HttpResponse의 인스턴스와는 달리
Servlet의 경우 싱글턴으로 관리되기에 WAS가 실행된 후 한 번 생성되면 서버가 종료될때까지
죽지 않고 살아있게 된다.
즉 서블릿 컨테이너는 처음 서블릿을 실행할 때 한 번 서블릿 객체를 생성하고(Init메서드),
이후 요청에 대해서는 생성했던 서블릿 객체를 지속하여 사용한다고 할 수 있다.(Service 메서드)
이 모든 것을 Servlet Container, 즉 WAS가 관리하고 담당한다고 할 수 있다.
하단의 그림이 해당 내용을 잘 설명하고 있다고 할 수 있다.
하단의 그림은 간단한 구조를 도식화하여 잘 보여주는 것 같아서 가져와봤다.
여기까지 오니 구체적 사례의 질문에서 출발한 내 궁금증이 다소 해결되었다.
또 위의 내용을 정리하고 나니 아래의 그림이 보다 더 선명하고 입체적으로 이해가 되었다.
즉, init 메서드를 통해서 생성된 서블릿이 WAS에 의해서 관리되다가
특정 HTTP 요청이 들어올 때마다 service 메서드를 호출하기 때문에
해당 메서드를 Override 함으로써 커스텀한 Servlet 객체를 생성하여
Servlet의 기능을 사용할 수 있었던 것이다.
A servlet life cycle can be defined as the entire process from its creation till the destruction. The following are the paths followed by a servlet.
- The servlet is initialized by calling the init() method.
- The servlet calls service() method to process a client's request.
- The servlet is terminated by calling the destroy() method.
- Finally, servlet is garbage collected by the garbage collector of the JVM.
상단의 그림과 4가지 문장이 서블릿 컨테이너의 라이프 사이클에 대해서 굉장히 압축적으로 설명하고 있다.
스프링부트만을 이용해서 개발을 하고있기 때문에 레거시한 코드도 만나본적 없고
깊숙한 원리에 대해서는 이해도가 부족하다.
그렇지만 아무래도 원리나 특정 기술이 발전하게 된 역사에 대해서 알고 또 공부하게되면
이전 기술 내지는 핵심원리에 대해서 이해가 반드시 선행되는 것 같다.
갈 길이 멀다.
참고