Post

Servlet 개념과 동작 방식 정리

Servlet 개념과 동작 방식 정리

📗 1. Servlet


스프링을 이해하려면 서블릿 컨테이너와 스프링 내의 스프링 컨테이너에 대해 알고 있어야 한다.

스프링 컨테이너와 서블릿 컨테이너에서 더 세부적으로 들어가, 서블릿이라는 개념에 대해 이해한 후에 점진적으로 넓혀가보자.

📌 서블릿이란?

우선, 서블릿이란 웹 서버나 애플리케이션 서버에서 실행되는 자바 프로그램으로, 웹 서버로부터 HTTP 통신을 통해, 요청을 수신하고, 처리하여, 다시 응답하는 역할을 한다.

과거에는 서버에서 정적인 자료(HTML)만 주고 받을 수 있어, 클라이언트가 자료를 요청하면 서버는 미리 만들어진 자료를 저장하고 있다가 반환했다.

하지만 인터넷 사용자가 많아지면서, 사용자는 정적인 자료가 아닌 자신에게 맞는 자료를 요구하기 시작했고, 사용자 요구에 맞춰 동적으로 반응하는 페이지를 만들기 위해 서블릿이 만들어진 것이다.

서블릿은 다양한 유형의 요청에 대해 응답 가능해서 서버의 기능을 확장하고, 웹서버에서 웹 애플리케이션을 호스팅하는 웹 컨테이너와 같은 역할을 한다.

거의 모든 client-server 프로토콜을 지원하지만, HTTP와 함께 사용되는 경우가 많아 HTTP 서블릿이라고도 부른다.

📌 클라이언트 - 서버 구조

다음, 클라이언트 - 서버 구조에 대해 알아보자.

image

  1. 사용자가 웹 서버로 HTTP 요청을 보낸다.
  2. 서버는 서블릿이 포함된 웹 컨테이너가 있는데, 이 서블릿은 데이터베이스에서 데이터를 수집하고, 응답을 생성한다.
  3. 서블릿이 생성한 응답은 HTTP 응답을 통해 클라이언트 브라우저로 전송된다.

여기서 서블릿이 생성한 응답을 어떻게 HTTP 응답 포맷으로 변환했을까?

웹 서버는 HTTP 프로토콜로만 동작하기 때문에, 웹 컨테이너에서 서블릿의 응답을 HTTP 응답으로 변환하는 작업을 담당한다.

📌 웹 컨테이너 (서블릿 컨테이너)

image

웹 컨테이너라고 알려진 서블릿 컨테이너는 Java EE 애플리케이션(jakarta 로 전환됨)의 런타임 환경을 제공한다.
(참고 : Java EE → Jakarta 전환 https://www.samsungsds.com/kr/insights/java_jakarta.html)

클라이언트/사용자는 서버에 정적 웹 페이지만 요청할 수 있다.
만약 사용자가 입력된 웹 페이지를 읽으려는 경우, Java의 웹 컨테이너에서 서블릿 API와 HTTP 요청 처리에 필요한 서비스를 구현한다.

웹 컨테이너는 다음의 작업을 처리한다.

  1. 서블릿 인스턴스의 init() 메소드를 호출하여 초기화 한다.
    • 최초 요청을 받았을 때 한번 초기화 하고 나면 그 다음 요청부터는 이 과정을 생략한다.(싱글톤 패턴 사용)
  2. 서블릿이 초기화 된 다음부터 클라이언트의 요청을 처리할 수 있다.
    각 요청은 별도의 쓰레드로 처리하고 이때 서블릿 인스턴스의 service() 메소드를 호출한다.
    • 이 안에서 HTTP 요청을 받고 클라이언트로 보낼 HTTP 응답을 만든다.
    • service()는 보통 HTTP Method에 따라 doGet(), doPost() 등으로 처리를 위임한다.
    • 따라서 보통 doGet() 또는 doPost()를 구현한다.
  3. 서블릿 컨테이너 판단에 따라 해당 서블릿을 메모리에서 내려야 할 시점에 destroy()를 호출한다.

💡
Servlet 클래스의 service() 메서드를 호출하여 요청된 URL과 일치하는 Servlet을 시작한다.

주어진 HTTP 요청에 대해 호출되는 service() 메서드는 웹 컨테이너 프로토콜 내, 별도의 스레드에서 처리된다.

💡
애플리케이션 서버 VS 서블릿 컨테이너
애플리케이션 서버는 동적인 컨텐츠를 만드는 서버로, Java EE(EJB, JMS, CDI, JTA, Servlet)의 전체를 지원하고,
서블릿 컨테이너는 서블릿 API에 대해서 지원하는 서버이다.

※참고 : https://pjh3749.tistory.com/267


📗 2. Servlet 동작 방식


image

  1. 사용자(클라이언트)가 URL을 입력하면 HTTP Request가 웹 서버로 전달된다.
  2. 웹 서버는 요청을 Servlet Container(웹 컨테이너)로 전달한다.
  3. 요청을 전송받은 Servlet Container(웹 컨테이너)HttpServletRequest, HttpServletResponse 객체를 생성한다.
  4. web.xml을 기반으로 사용자가 요청한 URL이 어느 서블릿에 대한 요청인지 찾는다.
  5. 해당 서블릿에서 service() 메소드를 호출한 후 클라이언트의 GET, POST 여부에 따라 doGet() 또는 doPost()를 호출한다.
  6. doGet() 또는 doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse 객체에 응답을 보낸다.
  7. 응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킨다.

📌 HTTP 요청 처리 순서

image

  1. 사용자는 웹 서버에 HTTP 요청을 보낸다.
  2. 웹 서버는 요청을 웹 컨테이너로 전달한다.
  3. 웹 컨테이너는 HTTP 요청 메시지를 파싱한 후 request, response 객체를 생성한다.
  4. 웹 컨테이너는 web.xml 또는 @WebServlet을 기반으로 요청 URL과 매핑된 서블릿 객체를 찾는다.
  5. 해당 서블릿이 최초 요청인 경우, 서블릿 객체를 생성(init()) 메서드를 호출한 뒤, service() 메서드를 호출해 비즈니스 로직을 수행한다.
  6. 웹 컨테이너는 response 객체에 담긴 데이터로 HTTP 응답 메시지를 생성하고 웹 서버에 전송한다.
  7. 웹 서버는 HTTP 응답을 통해 클라이언트에게 응답을 다시 보낸다.
  8. 전송 완료 후, 웹 컨테이너는 request, response 객체를 소멸시킨다.

💡
※ 순서 :
클라이언트 → 웹 서버 → 웹 컨테이너(서블릿 컨테이너) → 서블릿
→ 웹 컨테이너(서블릿 컨테이너) → 웹 서버 → 클라이언트


📗 3. 라이프사이클


서블릿 라이프사이클은 생성부터 소멸까지의 과정을 의미하며, 각 단계마다 호출하여 기능을 수행하는 콜백 메서드로 구성된다.

다음은 수명 주기 단계이다.

  • init()

    한 번만 호출되며, 서블릿이 생성될 때만 호출되어 일회성 초기화에 사용된다.

    일반적으로 서블릿은 사용자가 서블릿에 해당하는 URL을 처음 호출할 때 생성되지만, 서버가 처음 시작될 때 어떤 서블릿을 로드할지 지정할 수도 있다.

  • service()

    실제 작업을 수행하는 주요 메서드이다. 웹 컨테이너(서블릿 컨테이너)는 클라이언트의 요청을 처리하기 위해 service() 메서드를 호출한다.

    서버가 서블릿 요청을 받을 때마다 웹 컨테이너는 새 스레드를 생성하고, service() 메서드를 호출한다.
    이 메서드는 HTTP 요청 유형(GET, POST, PUT, DELETE 등)을 확인하고, 적절하게 doGet, doPost, doPut, doDelete 등의 메서드를 호출한다.

  • destroy()

    서블릿의 수명 주기가 끝날 때 한 번만 호출된다.
    이 메서드는 서블릿에 데이터베이스 연결을 닫고, 백그라운드 스레드를 중단하고, 기타 정리 작업을 수행할 기회를 제공한다.

    destroy() 메서드가 실행되면 서블릿 객체는 가비지 컬렉션(JVM) 대상으로 표시된다.

  • 마지막으로, 서블릿 객체는 JVM의 가비지 컬렉터에 의해 가비지 수집된다.

image

  • 서블릿 인터페이스

```java package javax.servlet; … public interface Servlet { // 초기화 void init(ServletConfig config) throws ServletException;

1
2
3
4
5
6
7
8
9
ServletConfig getServletConfig();

void service(ServletRequest request, ServletResponse response)
    throws ServletException, IOException;

String getServletInfo();

// 소멸
void destroy(); }
This post is licensed under CC BY 4.0 by the author.