서블릿(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 |