본문 바로가기

Spring Boot

서블릿(Servlet)

서블릿(Servlet)

 

강사님께서 계속 말씀해주셨던 서블릿이 대체 뭐냐???????

들어도 모르겠으니 적으면서 이해한다

 

서블릿은 Java 언어로 된 서버 측 웹 컴포넌트(부품)로, 사용자의 요청(Request)을 받아 서버에서 처리한 결과를 HTTP 응답(Response)으로 반환하는 기술임.

자바 진영에서 웹 애플리케이션을 구현하기 위한 가장 기초적인 표준이며, Java EE(현재는 Jakarta EE)의 일부로 정의되어 있음

서블릿은 javax.servlet 및 javax.servlet.http 패키지를 통해 제공되며 일반적으로 HttpServlet 클래스를 상속하여 사용함

 

 

등장배경

초기 웹서버는 정적 HTML 파일만 제공할 수 있었다

동적인 웹페이지를 만들기 위해 Perl, Shell 기반의 CGI(Common Gateway Interface)가 주로 사용되었음

이 CGI에게는 한계가 있었다

 - 요청마다 새로운 프로세스를 생성해서 성능 저하

 - 복잡한 상태 관리와 요청 분기 처리의 어려움

 - 프로세스간 자원 공유의 부재

 

이를 해결하기 위해 Java기반 고성능 웹 서버 컴포넌트로 Servlet이 나왔음

 - 프로세스가 아닌 스레드 기반 처리로 고성능 제공

 - 객체지향 방식으로 코드 구조화

 - 세션, 쿠키, 리다이렉션 등 HTTP 기능 손쉽게 사용 가능

 - 다양한 WAS(Web Application Server, 이하 WAS)에서 표준적으로 작동함(Tomcat, Jetty 등)

 

 

서블릿 작동 흐름

Browser - > HTTP request - > Servlet container - > Servlet class doGet/doPost() / Response generation

브라우저 - > HTTP 요청 - > 서블릿 컨테이너 - > 서블릿 클래스의 doGet/doPost() 메서드 / 실행 - > 응답 생성

 

Servlet 클래스 예시

import jakarta.servlet.http.HttpServlet; // jakarta.servlet.http.HttpServlet
import jakarta.servlet.http.HttpServletRequest; 
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet(name = "helloServlet", urlPatterns  "/hello")
public class HelloServlet extends HttpServlet { // 상속
	@Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    						// 인자로 HttpServletRequest(요청), HttpServletResponse(응답)
    throw IOException {
    	response.setContentType("text/plain"); // 응답
        response.setCharacterEncoding("UTF-8"); // 응답
        response.getWriter().write("Hello Servlet!"); // 응답
    }
}

 

@WebServlet : 해당 클래스(HelloServlet)를 서블릿으로 등록(name = "helloServlet")하여,

어떤 경로(urlPatterns = "/hello")로 요청이 들어왔을 때 실행할지를 지정함

doGet() : HTTP GET(조회) 요청을 처리하는 메서드

HttpServletRequest : 요청 정보 객체(파라미터, 헤더 등)

HttpServletResponse : 응답 정보 객체(헤더, 상태코드, 본문 등 구성가능)

 

전통적 서블릿 기반 웹 앱의 디렉토리 구조 예시, 서블릿 디렉토리는 이렇게 만듬

myWebApp/src/main/java/com/example/HelloServlet.java

myWebApp/src/main/webapp/

 ㄴ WEB-INF/web.xml

 ㄴ index.jsp

 

* web.xml에서 서블릿을 수동으로 등록할 수도 있으며 최신 Java EE 환경에서는 어노테이션 방식이 선호된다.

 

 

Servlet API 핵심 인터페이스/클래스

HttpServlet 서블릿의 기본 구현체로, 대부분 이 클래스를 상속한다.(extends)
ServletRequest 클라이언트 요청 정보를 담고 있는 인터페이스(Request)
ServletResponse 클라이언트에 응답 데이터를 전송하는 데 사용한다(Response)
ServletContext 웹 애플리케이션의 전역 설정 및 자원을 공유하는 객체
HttpSession 클라이언트의 상태를 유지하기 위한 세션 기능들 제공

 

*

 - 서블릿의 단독 사용보다는 Spring과 같은 프레임워크 기반 기술로 이해하는것이 중요하다..

 - Spring MVC는 결국 내부적으로 DispatcherServlet이라는 서블릿을 통해 모든 요청을 처리한다

 - 서블릿 기술을 이해하면 Spring 요청 흐름 구조를 더 깊이 이해할 수 있다

 

 

서블릿의 생명주기(Lifecycle)

서블릿은 클라이언트의 요청이 있을 때마다 새롭게 생성되는것이 아니고

서블릿 컨테이너가 생명주기를 제어한다. 컨테이너는 서블릿 객체를 단 한번 생성하고 여러 요청을 반복해서 처리하도록 유지한다.

서블릿 컨테이너가 서블릿 객체의 생명주기를 제어하고, 객체 생성 후 여러 요청을 반복해서 처리하도록 유지하는 구조는

성능을 높이고 자원을 효율적으로 관리할 수 있게 한다.

 

 - 서블릿 생명주기의 단계별 설명

  메서드  
1단계 생성자 호출 서블릿 클래스의 인스턴스 최초 생성(기본 생성자)
2단계 init() // initiation? 최초 요청시 1회 호출됨.
3단계 service() 클라이언트의 요청이 들어올때마다 실행. GET, POST, PUT, PATCH, DELETE 등 구분없이 처리함
4단계 doGet() / doPost() service() 내부에서 HTTP 메서드에 따라 분기 실행됨
5단계 destroy() WAS(Web Application Server) 또는 서블릿이 제거될때 1회 호출. 자원을 정리합니다

 

Servlet 클래스 로드 및 인스턴스 생성 - > init() 1회 실행 - > service() 요청마다 실행 - > doGet() / doPost() 메서드 분기마다 실행

- > destroy() WAS 종료시 1회 실행

 

서블릿 생명주기 예제

@WebServlet(name = "lifeCycleServlet", urlPatterns = "/lifecycle") // 동일
public class LifeCycleServlet extends HttpServlet {
	public LifeCycleServlet() { // 생성자
    	System.out.println("1. 생성자 호출(Servlet 인스턴스 생성)");
    }
    
    @Override // Servlet 메서드들은 전부 Override인것 같다
    public void init() throws ServletException { // 최초 1회 실행
    	System.out.println("2. init() 호출 - 초기화 로직 수행");
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    	throw IOException { // doGet / doPost()는 HTTP 메서드에 따라 분기별로 실행된다고 함
    		System.out.println("3. doGet() 호출 - 요청 처리");
            response.setContentType("text/plain"); // ContentType, HTTP에 보낼 형식 지정
            response.getWriter().write("Hello Servlet LifeCycle!"); // 그럼 이걸 text로 출력하는듯
    }
    
    @Override
    public void destroy() { // Web Application Server 종료시 1회 실행
    	System.out.println("4. destroy() 호출 - 자원 해제");
    }
}

 

init() : DB연결 / 설정 파일 로드 등 초기화 처리하는 역할을 함. 생성자

servlet() : 요청마다 실행, GET / POST / PUT / PATCH / DELETE 등 메서드에 따라  doGet() 이런식으로 만들어서 분기처리함

doGet(), doPost() : service()에서 위임받아 실행함, 여기에서 실질적인 비즈니스 로직을 구현한다.

destroy() : WAS가 서블릿을 제거할 때 1번 실행, 커넥션 정리 및 로그 정료 등 자원 해제

 

*

서블릿은 싱글톤(Singleton) 구조로 동작하기 때문에 스레드 간 공유자원에 주의해야한다.

 - Singleton은 유일한 단일 인스턴스로 중복을 허용하지 않는다..

init()은 자주 변경되지 않는 설정이나 공통 자원을 준비하는데 적합하며,

destroy()에서는 꼭 자원 정리를 해야 메모리 누수를 방지할 수 있다

 

 

서블릿 컨테이너의 역할

Servlet Container는 서블릿이 실행될 수 있는 환경과 HTTP 통신을 위한 핵심 기능을 제공하는 서버 측 컴포넌트이다.

서블릿의 생명주기를 관리한다.

Java EE 스펙의 웹 애플리케이션 서버는 반드시 서블릿 컨테이너를 포함하고 있으며,

Spring Boot에서도 Tomcat을 내장해서 이를 자동으로 제공하고 있다.

 

 - 서블릿 컨테이너의 핵심 역할.... 얘 하는게 엄청 많네.. 그냥 서블릿의 처음부터 끝까지 관리한다고 생각하면 될 것 같다.

서블릿 클래스 관리 서블릿 인스턴스 생성(생성자), 초기화(init()), 요청 분배(service), 소멸(destroy) 등 생명주기 관리
요청 - 응답 처리 HTTP Request를 파싱하고 Response를 생성하여 전송한다(Socket 기반 통신 처리 포함)
멀티 스레드 처리 각 요청을 별도의 스레드로 처리한다(Thread-per-request)
매핑 처리 URL과 서블릿을 연결하여 어떤 서블릿이 실행될지 결정한다
보안 및 세션 관리 쿠키, 세션, 인증, HTTPS, 보안 필터 등을 관리한다.
예외 및 에러 처리 HTTP 오류 코드에 따라 자동 처리 페이지를 제공한다.(404 등)

 

요청 - > 응답의 흐름

브라우저(HTTP 요청) - > Connector(Socket) - > Request(요청) 객체 생성 - > Context 및ㅊ URL 맵핑 탐색 

- > Wrapper에서 해당 서블릿을 호출한 후 service() > doGet() 혹은 doPost() - > Response(응답) 객체 작성

- > Socket을 통해 응답을 전송함 - > 브라우저 화면에 출력

출처 : 강사님 자료

 

톰캣(Tomcat) 내부 구조를 이해하기(매우 간단)

 - Engine(전체 톰캣 인스턴스) - > Host(예 : localHost) - > Context(하나의 웹 애플리케이션(WAR)

- > Wrapper(하나의 서블릿 객체와 URL을 맵핑한다)

 

하나의 Tomcat 인스턴스에는 여러개의 Context(WebApp)가 존재할 수 있으며 각 Context에는 여러개의 서블릿을 포함한다.

 

 

주요 서블릿 컨테이너의 종류

 

컨테이너  
Tomcat 가장 널리 사용되는 오픈소스 서블릿 컨테이너. Spring Boot에도 기본 내장되어있음
Jetty 제티 / 빠르고 경량회된 서블릿 컨테이너. IoT, 경량 서비스에 적합하다
Undertow 논블로킹(비동기화 같은것) 기반 처리로 고성능 제공.. Spring WebFlux와 잘 호환된다
Resin 고성능 기업용 상용 컨테이너

 

*

 - Servlet은 Singleton으로 관리되기 때문에 스레드간 공유자원 사용 시 동기화 처리가 필수이다.

 - 실제로 HTTP 요청과 응답이 어떻게 전달되는지 디버깅하려면,

   Tomcat 로그 또는 필터를 활용해서 HttpServletRequest / HttpServletResponse로 로그를 찍어보세요?

 

 


Spring Boot와 내장 서블릿 컨테이너

스프링부트는 전통적 WAR 배포 방식이 아니라 서블릿 컨테이너를 내장(Embedded)하여 애플리케이션을 JAR 파일로 직접 실행할 수 있게 해준다.

내장 톰캣 구조인데.. 이게 머고..

 

 

Spring Boot 주요 설정

Spring Boot에 있는 build.gradle - > dependencies(의존성 주입, DI)에 포함시키면 자동으로 톰캣을 내장한다.

implementation 'org.springframework.boot:spring-boot-starter-web'

이걸 포함시키고

@SpringBootApplication
public class DemoApplication {
	public static void main(String[] args) {
    	SpringApplication.run(DemoApplication.class, args); // 톰캣 내장 실행
        // 이걸 기본으로 작성한다
    }
}

 

*

 - 서블릿 생명주기 훅(init, destroy)은 실제 프로젝트에서 연결 풀 초기화나 로그 설정 등에 사용할 수 있다.

 - 내장 톰캣을 사용하는 Spring Boot는 실행이 간편하지만, WAS 분리 배포가 필요한 기업 환경에선 외부 톰캣 설정을 선호할 수 있다.

 - Servlet API를 사용하는 로우레벨 코드 작성보단 Spring MVC의 추상화된 구조를 활용하는게 유지보수에 유리하다.

 

 

Servlet : 자바 기반 HTTP 요청 처리용 클래스

Servlet Lifecycle : init - > service - > doGet/doPost - > destroy

Servlet Container : 서블릿을 실행하고 관리하는 환경임(톰캣이 대표적)

Spring Boot 내장 컨테이너 : 톰캣, 제티, 언더토우 등을 내장하여 JAR 실행 가능

 

 

아.. 어렵네..

 

'Spring Boot' 카테고리의 다른 글

Spring MVC의 컴포넌트  (0) 2025.07.02
Spring MVC  (2) 2025.07.02
HTTP 프로토콜 기초  (3) 2025.07.01
Spring AOP가 필요한 이유  (1) 2025.07.01
DTO  (2) 2025.06.26