서블릿,필터,리스너 보충자료
1. 서블릿 필터(Filter)
역할
요청(request) 및 응답(response) 데이터 처리: 클라이언트로부터 들어오는 요청을 가로채거나, 서블릿이나 JSP가 응답을 생성한 후 이를 가로채 추가 처리를 수행합니다.
주로 다음과 같은 작업에 사용됩니다:
요청/응답 데이터 수정
요청 로깅 및 모니터링
인증 및 권한 검사
데이터 압축 (예: GZIP)
CORS 설정 등
동작 방식
클라이언트의 요청이 서버로 들어오면, **필터 체인(Filter Chain)**이 실행됩니다.
필터는 요청을 처리하거나, 필요한 경우 요청을 다음 필터나 서블릿으로 전달합니다.
서블릿이 응답을 생성하면, 필터가 응답을 가로채 필요한 처리를 수행한 뒤 클라이언트로 보냅니다.
동작 순서
web.xml
또는@WebFilter
에 등록된 필터는 순서대로 실행됩니다.필터 체인의 흐름:
요청(Request) → 필터1 → 필터2 → 서블릿 → 필터2 → 필터1 → 응답(Response)
필터 구현 방법
javax.servlet.Filter
인터페이스 구현.주요 메서드:
init(FilterConfig config)
: 필터 초기화.doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
: 요청/응답 처리.destroy()
: 필터 종료 처리.
@WebFilter("/*") // 모든 요청에 대해 적용
public class LoggingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("Request received at " + new Date());
chain.doFilter(request, response); // 다음 필터나 서블릿으로 요청 전달
System.out.println("Response sent at " + new Date());
}
}
2. 서블릿 리스너(Listener)
역할
이벤트 기반 동작: 웹 애플리케이션의 특정 이벤트(예: 시작, 종료, 세션 생성/소멸 등)를 감지하고 처리합니다.
주요 사용 사례:
애플리케이션 초기화 작업 (예: 리소스 로딩, 데이터베이스 연결 설정).
세션 추적 (예: 로그인 사용자 수 추적).
리소스 정리 (예: 데이터베이스 연결 종료).
동작 방식
리스너는 특정 이벤트가 발생할 때 자동으로 호출됩니다.
웹 컨테이너는 이벤트 발생 시 리스너를 실행하여 적절한 작업을 수행합니다.
동작 순서
애플리케이션 시작 시 등록된 리스너가 호출됩니다.
세션 관련 이벤트가 발생하면, 관련 리스너가 실행됩니다.
애플리케이션 종료 시 종료 이벤트 리스너가 호출됩니다.
리스너 종류
ServletContextListener:
애플리케이션 시작/종료 이벤트 처리.
주요 메서드:
contextInitialized(ServletContextEvent event)
: 애플리케이션 초기화 작업.contextDestroyed(ServletContextEvent event)
: 애플리케이션 종료 작업.
HttpSessionListener:
세션 생성/소멸 이벤트 처리.
주요 메서드:
sessionCreated(HttpSessionEvent event)
: 세션 생성 시 호출.sessionDestroyed(HttpSessionEvent event)
: 세션 종료 시 호출.
ServletRequestListener:
요청(Request) 생성/소멸 이벤트 처리.
주요 메서드:
requestInitialized(ServletRequestEvent event)
: 요청 초기화 시 호출.requestDestroyed(ServletRequestEvent event)
: 요청 종료 시 호출.
리스너 구현 방법
리스너 인터페이스를 구현.
@WebListener
또는web.xml
에 등록.
@WebListener
public class AppContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("Application started!");
}
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Application stopped!");
}
}
3. 필터와 리스너의 차이점
특징
필터(Filter)
리스너(Listener)
동작 방식
요청/응답을 가로채 처리
특정 이벤트를 감지하고 처리
목적
요청/응답 전후 데이터 변경, 인증, 로깅 등
애플리케이션, 세션, 요청의 상태 변화 감지
실행 시점
요청이 들어오거나 응답이 생성될 때 실행
애플리케이션/세션/요청의 생명 주기 이벤트 발생 시 실행
등록 방법
@WebFilter
또는 web.xml
@WebListener
또는 web.xml
체인 구조
필터 체인으로 연결되어 동작
독립적으로 동작
4. 필터와 리스너의 동작 순서
애플리케이션 초기화:
ServletContextListener.contextInitialized
실행.초기화 작업(예: 설정 파일 로딩, 데이터베이스 연결).
클라이언트 요청 처리:
ServletRequestListener.requestInitialized
실행.필터 체인 실행: 요청 → 필터1 → 필터2 → 서블릿.
서블릿 처리 후 응답 생성 → 필터 체인 응답 처리: 필터2 → 필터1.
ServletRequestListener.requestDestroyed
실행.
세션 관련 이벤트:
세션 생성 시:
HttpSessionListener.sessionCreated
실행.세션 종료 시:
HttpSessionListener.sessionDestroyed
실행.
애플리케이션 종료:
ServletContextListener.contextDestroyed
실행.종료 작업(예: 리소스 정리, 로그 기록).
5. 필터와 리스너를 함께 사용하는 예시
필터:
모든 요청에 대해 로깅.
특정 API에 대해 인증 처리.
리스너:
애플리케이션 시작 시 설정 파일 로드.
세션 생성/종료 시 사용자 활동 로그 기록.
생명주기
서블릿 생명주기의 주요 단계
서블릿 생성 (Initialization)
서블릿 컨테이너는 서블릿 객체를 메모리에 로드하고 초기화합니다.
초기화는
init()
메서드를 통해 이루어지며, 서블릿이 최초로 요청되기 전에 한 번만 호출됩니다.
요청 처리 (Request Handling)
클라이언트가 서블릿에 요청을 보내면 컨테이너는
service()
메서드를 호출하여 요청을 처리합니다.service()
메서드는 HTTP 요청 메서드(GET, POST 등)에 따라 적절한doGet()
,doPost()
등의 메서드를 호출합니다.
서블릿 소멸 (Destruction)
애플리케이션 종료 시 또는 서블릿이 더 이상 필요 없을 때, 컨테이너는 서블릿 객체를 소멸시킵니다.
소멸 시
destroy()
메서드가 호출되며, 리소스 정리(예: 데이터베이스 연결 종료, 스레드 정리 등)를 수행할 수 있습니다.
서블릿 생명주기 메서드
1. init()
init()
호출 시점: 서블릿이 처음 생성될 때 한 번 호출됩니다.
목적: 서블릿의 초기화 작업 수행 (예: 설정 파일 읽기, 데이터베이스 연결 설정).
예시:
@Override public void init() throws ServletException { System.out.println("Servlet is being initialized"); }
2. service()
service()
호출 시점: 클라이언트 요청이 있을 때마다 호출됩니다.
목적: 요청에 따라 적절한 메서드(
doGet
,doPost
)를 호출.컨테이너 동작: 요청 메서드(GET, POST 등)에 따라
doGet()
또는doPost()
메서드로 분기.예시:
@Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Processing request"); super.service(req, resp); // 부모 클래스의 service() 호출 }
3. destroy()
destroy()
호출 시점: 서블릿이 컨테이너에서 제거될 때 호출됩니다.
목적: 리소스 정리(예: 열려 있는 파일이나 데이터베이스 연결 종료).
예시:
@Override public void destroy() { System.out.println("Servlet is being destroyed"); }
생명주기 흐름 (Lifecycle Flow)
서블릿 로드 및 초기화:
웹 애플리케이션이 시작되거나 서블릿에 처음 요청이 들어올 때 서블릿 클래스가 로드됩니다.
컨테이너는 서블릿 객체를 생성하고,
init()
메서드를 호출합니다.
요청 처리:
클라이언트의 HTTP 요청이 들어오면, 컨테이너는
service()
메서드를 호출합니다.service()
는 요청 타입에 따라doGet()
,doPost()
등 적절한 메서드를 실행합니다.
서블릿 소멸:
웹 애플리케이션이 종료되거나 서블릿이 필요 없게 되면, 컨테이너는
destroy()
메서드를 호출하여 서블릿을 소멸시킵니다.
서블릿 생명주기의 단계별 예시 코드
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class MyServlet extends HttpServlet {
// 1. 초기화 단계
@Override
public void init() throws ServletException {
System.out.println("Servlet Initialized");
}
// 2. 요청 처리 단계
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("Handling GET request");
resp.getWriter().write("Hello, World!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("Handling POST request");
resp.getWriter().write("POST request received");
}
// 3. 소멸 단계
@Override
public void destroy() {
System.out.println("Servlet Destroyed");
}
}
생명주기와 멀티스레드
서블릿은 기본적으로 멀티스레드 환경에서 실행됩니다.
하나의 서블릿 객체가 여러 클라이언트 요청을 동시에 처리하므로, 스레드 안전성에 주의해야 합니다.
서블릿 인스턴스 변수(멤버 변수) 사용 시 동기화가 필요합니다.
지역 변수는 스레드 안전하므로 선호됩니다.
주의 사항
init()
은 한 번만 호출됨:서블릿 객체는 싱글톤으로 생성되며,
init()
은 한 번만 호출됩니다.
service()
는 요청마다 호출됨:클라이언트 요청이 올 때마다 호출되므로, 비즈니스 로직을 구현하는 핵심 메서드입니다.
destroy()
는 마지막 정리 작업에 사용:리소스 정리 코드를 반드시 작성해야 메모리 누수를 방지할 수 있습니다.
애플리케이션 종료 시 동작:
서블릿 컨테이너가 종료되거나 서블릿이 언로드될 때
destroy()
가 호출됩니다.
Last updated