Backend/JAVA

서블릿이란 무엇인가 [서블릿 실행 흐름 편]

뜨거운 개발자 2024. 5. 8. 09:06

 

예제 실행 상황 및 파일

서블릿 컨테이너는 메인 서버에 위치하며, 웹 애플리케이션은 서블릿 컨테이너에 배포됩니다.

이 예시 그림에서는 ServletFlow라는 웹 어플리케이션이 존재하고 WEB-INF라는 폴더에 URL 매핑 정보가 서블릿 이름과 연결 되어있습니다.

브라우저를 사용해 클라이언트 데이터가 포함된 HTTP 요청을 서버에 전송하고, 서버로부터 HTTP 응답을 받습니다.

web.xml 파일과 "HelloServlet.java"의 .class 파일을 저장하는 classes 폴더가 있습니다.

 

index.html

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="ISO-8859-1"> 
<title>Home</title> 
</head> 
<body> 
    <form action="hello" method="post"> 
  
        Enter your name and click on submit:  
        <input type="text" name="name" /> 
        <input type="submit" /> 
    </form> 
</body> 
</html>

HelloServlet.java

package com; 
  
import java.io.IOException; 
import java.io.PrintWriter; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
  
public class HelloServlet extends HttpServlet { 
    private static final long serialVersionUID = 1L; 
  
    protected void doPost(HttpServletRequest request, 
                          HttpServletResponse response) 
        throws ServletException, IOException 
    { 
  
        // Get the client entered data from request object 
        String name = request.getParameter("name"); 
  
        // set the response content type 
        response.setContentType("text/html"); 
        PrintWriter out = response.getWriter(); 
  
        // Print hello message to the client browser in 
        // response object 
        out.println("<h3>Hello " + name + "!!</h3>"); 
        out.close(); 
    } 
}

web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> 
  <display-name>ServletFlow</display-name> 
  <welcome-file-list> 
    <welcome-file>index.html</welcome-file> 
  </welcome-file-list> 
  <servlet> 
    <servlet-name>HelloServlet</servlet-name> 
    <servlet-class>com.HelloServlet</servlet-class> 
  </servlet> 
  <servlet-mapping> 
    <servlet-name>HelloServlet</servlet-name> 
    <url-pattern>/hello</url-pattern> 
  </servlet-mapping> 
</web-app>

서버 시작 후 서블릿 컨테이너의 역할

  1. 모든 웹 애플리케이션을 인식합니다.
  2. 각 웹 애플리케이션을 배포합니다.
  3. 각 애플리케이션에 대해 별도의 객체를 준비합니다. 이 객체가 바로 ServletContext 객체입니다. (web.xml을 기반으로 만들어졌습니다.)

웹 애플리케이션 배포 중에 일어나는 일

  • 컨테이너는 "WEB-INF" 폴더 아래에 있는 web.xml 파일을 인식합니다.
  • web.xml 파일을 식별한 후, 컨테이너는 파일을 로드, 파싱, 읽기 과정을 거칩니다.
  • web.xml 파일에 display names 또는 context parameters와 같은 application-level data가 있으면, 컨테이너는 해당 데이터를 ServletContext 객체에 저장합니다. 이 데이터는 servletContext 객체에 의해 관리됩니다.

welcome page load

  <welcome-file-list> 
    <welcome-file>index.html</welcome-file> 
  </welcome-file-list> 
  • 이제 컨테이너는 web.xml 파일에 명시된 welcome-file-list를 기준으로 클라이언트 브라우저에 표시할 환영 파일 페이지를 식별합니다.
  • 여기서는 "index.html"을 환영 파일로 지정했으므로 브라우저에 해당 HTML 페이지가 표시됩니다.
  • URL: http://localhost:8081/ServletFlow/
  • index.html 페이지에서 이름을 입력하고 "Submit" 버튼을 클릭하면, 프로토콜을 통해 클라이언트가 입력한 데이터가 요청으로 전송됩니다.

1. 클라이언트 요청

  1. 요청은 크게 두가지 header와 body부분으로 나누어진 request format 을 지키고 있습니다.
    • Request headers: 클라이언트 브라우저에 관한 정보를 담고 있습니다. (HTTP header라고 이해하시면 됩니다.)
      • Request Method type, 프로토콜 정보, 클라이언트 브라우저가 수용하는 언어, 쿠키 정보, 인코딩 메커니즘 등이 포함됩니다.
    • Request body.: 클라이언트가 폼에 입력한 실제 데이터가 요청 파라미터로 저장됩니다.
  2. 프로토콜은 이 요청 형식을 메인 서버로 전달합니다.
  3. 서버는 요청이 유효한지 여부를 확인하고, 유효하다면 해당 요청을 서블릿 컨테이너로 전달합니다.
  4. 이제 컨테이너는 애플리케이션 이름과 실행할 리소스 이름을 식별합니다.

2. 컨테이너에서 서블릿 식별

  • 컨테이너는 확장자 및 리소스 이름을 기준으로 요청이 HTML 요청인지 확인합니다.
  • 폼에서 지정한 내용에 따라, 컨테이너는 URL 패턴(예: "hello")에 연결된 서블릿을 식별하고, 해당 .class 파일이 "classes" 폴더에 있는지 확인합니다.
  • 이를 식별하기 위해 컨테이너는 "WEB-INF" 폴더 및 web.xml 파일을 살펴봅니다.
  • web.xml 파일에서 매핑 세부 정보를 확인한 후, 컨테이너는 URL 패턴에 따라 특정 서블릿을 가져오고, 그 서블릿의 .class 파일을 찾기 위해 "classes" 폴더를 검색합니다.
  • 컨테이너가 서블릿의 .class 파일을 식별하면, 서블릿의 생명주기가 시작됩니다.

3. 서블릿 생명주기

1. 서블릿 로딩

  • 먼저 컨테이너는 서블릿 로딩을 수행합니다.
  • 컨테이너는 동일한 서블릿이 이미 존재하는지 확인하며, 존재하지 않는 경우 .class 파일을 로드하고, 바이트 코드를 메모리에 적재합니다.
  • 이를 위해 컨테이너는 내부적으로 **Class c = Class.forName("HelloServlet");**을 호출합니다.

2. 서블릿 인스턴스화

  • 서블릿 로딩 후, 서블릿 객체를 생성합니다.
  • 해당 서블릿을 위한 ServletConfig 객체를 생성하고, 그 서블릿의 모든 데이터를 그 안에 저장합니다.
  • 이를 위해 컨테이너는 내부적으로 **Object obj = c.newInstance();**를 호출합니다.

3. 서블릿 초기화

  • 이제 서블릿을 초기화해야 하며, 컨테이너는 ServletConfig 객체를 전달하여 init() 메서드를 호출합니다.
  • 먼저 파라미터가 있는 init() 메서드가 실행되며, 그 안에서 파라미터가 없는 init() 메서드가 제네릭 서블릿에서 호출되어 실행됩니다.

4. 서블릿 요청 처리

  • 이제 컨테이너는 HTTP 요청 및 HTTP 응답 객체와 doPost() 메서드를 실행할 스레드를 생성합니다.
  • **GenericServlet**의 경우, 컨테이너는 먼저 **GenericServlet**의 service() 메서드를 호출하며, 서블릿 Reqeust,Response 객체를 파라미터로 전달합니다.
  • 여기서는 HTTP 특정 요청이기 때문에, **HttpServlet**을 사용해 HttpServletRequestHttpServletResponse 객체를 전달하여 doPost() 메서드를 실행합니다.
  • 컨테이너는 doPost() 메서드를 실행하여 해당 요청을 처리합니다.

5. 응답 생성 및 전달

  • doPost() 메서드가 실행되면 응답은 응답 객체에 생성됩니다.
  • doPost() 메서드 실행이 끝나면 해당 스레드는 파괴되고, 컨테이너는 그 응답을 메인 서버에 전달합니다.
  • 메인 서버는 HTTP 응답을 프로토콜로 전송합니다.
  • 프로토콜은 응답 형식을 준비하며, 응답 헤더와 응답 본문으로 구성됩니다:
    • 응답 헤더: 어떤 유형의 응답이 오는지, 응답의 길이 등을 나타내는 메타데이터가 포함됩니다.
    • 응답 본문: 클라이언트 브라우저에 표시될 실제 동적 응답이 포함됩니다.

6. 응답 처리 및 종료

  • 프로토콜은 응답 객체를 클라이언트 브라우저로 전달합니다.
  • 브라우저는 응답 본문에서 데이터를 가져와 브라우저에 표시합니다.
  • 클라이언트 측에 응답이 표시되면 프로토콜은 클라이언트와 서버 간의 연결을 종료합니다.
  • 컨테이너는 클라이언트에게 응답이 전달된 것을 파악하고, 요청 객체와 응답 객체를 파괴합니다.

7. 컨테이너의 대기 상태

  • 이제 컨테이너는 추가 요청을 위해 대기 상태로 들어갑니다.
  • 컨테이너 구현과 애플리케이션 서버에 따라, 컨테이너는 서블릿을 파괴할 수도 있습니다.
    • 예를 들어, Tomcat 서버의 경우, 서버가 종료될 때까지 컨테이너가 서블릿을 유지합니다.
    • WebLogic 서버의 경우, 서버에 지정된 시간까지 서블릿을 파괴하지 않고 대기합니다.

8. 서블릿 파괴

  • 애플리케이션의 작업이 완료되고 서버가 중지되면, 컨테이너는 서블릿 구성 객체를 파괴하고 서블릿 객체를 파괴합니다.
  • 서블릿 객체 파괴는 destroy() 메서드를 호출하여 서블릿의 인스턴스를 해체하는 것입니다.
  • 컨테이너는 서블릿의 바이트 코드를 메모리에서 언로드하고 ServletContext 객체를 파괴합니다.

결론

Java 서블릿에는 main() 메서드가 없습니다. 서블릿 또는 요청 및 응답 객체를 처리할 새 스레드를 생성하는 것은 서블릿 컨테이너의 역할입니다.

단일 서블릿에서 여러 요청을 처리하기 위해 컨테이너는 여러 스레드를 생성합니다. 서블릿의 생명주기 이벤트를 모니터링하고 이에 대응하려면 리스너 객체를 정의할 수 있습니다. 생명주기 이벤트가 발생하면 리스너 객체의 메서드가 호출됩니다.

 

출처

아래 내용은 https://www.geeksforgeeks.org/servlet-flow-of-execution/ 해당 링크의 글을 읽고 이해를 바탕으로 한국어로 정리한 글입니다.

728x90

'Backend > JAVA' 카테고리의 다른 글

Servlet 이란 무엇일까 [개념편]  (0) 2024.05.07