자바 서블릿 (Java Servlet)
Java 서블릿, 필터, 리스너 가이드
1. 서블릿 (Servlet)
서블릿(Servlet)은 Java를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양을 말합니다. 서블릿은 Java EE 사양의 일부분으로, 웹 서버의 성능을 향상하기 위해 사용되는 자바 클래스입니다.
1.1 서블릿의 특징
- 플랫폼 독립적: Java로 작성되어 있어 어떤 서버 환경에서도 실행 가능합니다.
- 서버 측 프로그램: 클라이언트의 요청을 처리하고 응답을 생성합니다.
- 동적 웹 페이지 생성: 사용자의 요청에 따라 다양한 웹 페이지를 동적으로 생성할 수 있습니다.
- 효율적인 처리: 멀티스레딩을 지원하여 요청을 효율적으로 처리합니다.
- 확장성: 다양한 프로토콜과 방식으로 클라이언트 요청을 처리할 수 있습니다.
2. 서블릿의 생명주기
서블릿의 생명주기는 서블릿 객체의 생성부터 소멸까지의 전체 과정을 의미합니다. 서블릿 컨테이너(예: Tomcat)가 이 생명주기를 관리합니다.
2.1 생명주기 단계
- 로딩 및 인스턴스 생성
- 클라이언트의 첫 요청이 들어오면, 서블릿 컨테이너는 해당 서블릿 클래스를 로드합니다.
- 서블릿의 인스턴스를 생성합니다. (서블릿당 하나의 인스턴스만 생성됨)
- 초기화 - init() 메소드
- 서블릿 인스턴스가 생성된 후, 컨테이너는 init() 메소드를 호출합니다.
- init() 메소드는 서블릿의 생애주기 동안 단 한 번만 호출됩니다.
- 이 단계에서 서블릿의 초기화 작업(예: 데이터베이스 연결 설정)을 수행합니다.
- 요청 처리 - service() 메소드
- 초기화 후, 서블릿은 클라이언트의 요청을 처리할 준비가 됩니다.
- 각 클라이언트 요청에 대해 서블릿 컨테이너는 별도의 스레드를 생성하고 service() 메소드를 호출합니다.
- service() 메소드는 요청의 타입(GET, POST 등)에 따라 적절한 메소드(doGet(), doPost() 등)를 호출합니다.
- service() 메소드는 서블릿의 수명 동안 여러 번 호출될 수 있습니다.
- 소멸 - destroy() 메소드
- 서블릿 컨테이너가 서블릿을 제거하기로 결정하면(예: 애플리케이션 종료 시), destroy() 메소드를 호출합니다.
- destroy() 메소드는 서블릿의 생애주기 동안 단 한 번만 호출됩니다.
- 이 단계에서 서블릿이 사용한 자원을 해제하고 최종 작업을 수행합니다.
2.2 서블릿 실행 순서 예시
서블릿 컨테이너 시작
↓
클라이언트의 첫 요청 도착
↓
서블릿 클래스 로딩
↓
서블릿 인스턴스 생성
↓
init() 메소드 호출
↓
service() 메소드 호출 (요청마다 반복)
↓
애플리케이션 종료 또는 서블릿 언로드 결정
↓
destroy() 메소드 호출
↓
서블릿 인스턴스 소멸
2.3 주의사항
- init()과 destroy() 메소드는 서블릿의 수명 동안 각각 한 번씩만 호출됩니다.
- service() 메소드는 클라이언트의 각 요청마다 새로운 스레드에서 호출됩니다.
- 서블릿은 멀티스레딩 환경에서 동작하므로, 한개의 객체를 여러 클라이언트가 공유하기 떄문에 특정 클라이언트의 작업 결과를 서블릿의 인스턴스 필드에 보관하지 말아야합니다.
3. 서블릿 유형
3.1 Servlet 인터페이스
Servlet
인터페이스는 모든 서블릿이 구현해야 하는 기본 인터페이스입니다. 주요 메소드는 다음과 같습니다:
init(ServletConfig config)
: 서블릿 초기화service(ServletRequest req, ServletResponse res)
: 클라이언트 요청 처리destroy()
: 서블릿 종료getServletConfig()
: 서블릿 설정 정보 반환getServletInfo()
: 서블릿 정보 반환
3.2 GenericServlet 클래스
GenericServlet
은 Servlet
인터페이스를 구현한 추상 클래스입니다. 프로토콜에 독립적인 서블릿을 구현할 때 사용됩니다.
Servlet
인터페이스의 모든 메소드를 구현합니다 (단,service()
메소드는 추상 메소드로 남겨둡니다).- 서블릿 컨테이너와의 통신을 단순화합니다.
3.3 HttpServlet 클래스
HttpServlet
은 GenericServlet
을 상속받아 HTTP 프로토콜을 사용하는 웹 애플리케이션을 위한 추상 클래스입니다.
- HTTP 메소드에 따른 doGet(), doPost(), doPut(), doDelete() 등의 메소드를 제공합니다.
service()
메소드를 구현하여 요청 방식에 따라 적절한 do* 메소드를 호출합니다.
4. 서블릿 구현 예제
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>Hello, World!</h1>");
out.println("</body></html>");
}
}
5. 서블릿 필터 (Servlet Filter)
서블릿 필터는 클라이언트의 요청이 서블릿에 도달하기 전이나 서블릿의 응답이 클라이언트에게 돌아가기 전에 요청과 응답을 변경할 수 있는 재사용 가능한 Java 클래스입니다.
5.1 필터의 주요 특징
- 요청/응답의 헤더나 데이터를 검사하고 수정할 수 있습니다.
- 요청을 다른 리소스로 리다이렉트할 수 있습니다.
- 여러 필터를 체인으로 연결하여 순차적으로 실행할 수 있습니다.
5.2 필터의 생명주기
- 초기화:
init()
메소드 호출 - 필터링:
doFilter()
메소드 호출 - 소멸:
destroy()
메소드 호출
5.3 필터 구현 예제
import java.io.IOException;
import javax.servlet.*;
public class MyFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
// 필터 초기화 코드
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 요청 전처리
chain.doFilter(request, response); // 다음 필터 또는 서블릿으로 요청 전달
// 응답 후처리
}
public void destroy() {
// 필터 종료 시 정리 코드
}
}
5.4 필터의 용도
- 인증 및 권한 체크
- 로깅 및 감사
- 데이터 압축
- 인코딩 변환
- MIME 타입 체크
6. 서블릿 리스너 (Servlet Listener)
서블릿 리스너는 웹 애플리케이션의 다양한 이벤트를 감지하고 그에 반응하는 객체입니다. 이벤트는 애플리케이션, 세션, 요청 수준에서 발생할 수 있습니다.
6.1 리스너의 주요 특징
- 웹 애플리케이션의 상태 변화를 모니터링합니다.
- 이벤트 기반으로 동작하여 특정 상황에서 자동으로 실행됩니다.
- 애플리케이션의 초기화, 세션 관리, 속성 변경 등의 작업을 처리할 수 있습니다.
- 필터의 실행 순서는 서블릿 컨테이너의 내부 정책에 따라 결정되므로 필터 실행 순서를 제어할 수 없습니다.
6.2 주요 리스너 인터페이스
- ServletContextListener
- 웹 애플리케이션의 시작과 종료 이벤트를 처리합니다.
- 메소드:
contextInitialized()
,contextDestroyed()
- ServletRequestListener
- 요청의 시작과 응답 이벤트를 처리합니다.
- 메소드:
requestInitialized()
,requestDestroyed()
- HttpSessionListener
- HTTP 세션의 생성과 소멸 이벤트를 처리합니다.
- 메소드:
sessionCreated()
,sessionDestroyed()
6.3 리스너 구현 예제
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
System.out.println("웹 애플리케이션이 시작되었습니다.");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("웹 애플리케이션이 종료되었습니다.");
}
}
6.4 리스너의 용도
- 애플리케이션 시작 시 초기화 작업 수행 (데이터베이스 연결, 설정 로드 등)
- 애플리케이션 종료 시 리소스 정리
- 세션 기반의 사용자 활동 추적
- 애플리케이션의 상태 모니터링 및 로깅
- 실시간 애플리케이션 통계 수집
6.5 리스너 등록
리스너는 두 가지 방법으로 등록할 수 있습니다:
- 어노테이션 사용:
@WebListener public class MyListener implements ServletContextListener { // ... }
- web.xml 파일에 등록:
<listener> <listener-class>com.example.MyListener</listener-class> </listener>
7. 서블릿 실행 순서
7.1 웹 애플리케이션 시작 시 순서
- ServletContextListener의 contextInitialized() 메소드 호출
- 필터 초기화 (init() 메소드 호출)
- 서블릿 초기화 (init() 메소드 호출, load-on-startup 값에 따라 순서 결정)
7.2 클라이언트 요청 처리 순서
- HttpSessionListener의 sessionCreated() 메소드 호출 (새 세션인 경우)
- ServletRequestListener의 requestInitialized() 메소드 호출
- 필터 체인 실행 (doFilter() 메소드)
- 요청 전처리
- 서블릿의 service() 메소드 호출 (일반적으로 doGet(), doPost() 등의 메소드로 위임)
- 필터 체인 실행 (doFilter() 메소드의 나머지 부분)
- 응답 후처리
- ServletRequestListener의 requestDestroyed() 메소드 호출
7.3 세부 실행 순서 예시
Client Request
↓
HttpSessionListener (if new session)
↓
ServletRequestListener
↓
Filter 1 (pre-processing)
↓
Filter 2 (pre-processing)
↓
Servlet (service method)
↓
Filter 2 (post-processing)
↓
Filter 1 (post-processing)
↓
ServletRequestListener
↓
Response to Client
7.4 웹 애플리케이션 종료 시 순서
- 서블릿 소멸 (destroy() 메소드 호출)
- 필터 소멸 (destroy() 메소드 호출)
- ServletContextListener의 contextDestroyed() 메소드 호출
Leave a comment