특정 이벤트 시점에 자동 실행되는 훅(hook)
필터는 요청이 들어올 때마다 실행되는 공통 처리 장치였다.
즉 “요청 흐름 중간”에 끼어드는 방식이다.
반면 어떤 작업은 “요청이 올 때마다”가 아니라
특정 시점에 한 번만 실행되는 게 더 자연스럽다.
예를 들어 이런 것들이다.
- 애플리케이션이 시작될 때 초기화 작업을 하고 싶다
- 애플리케이션이 종료될 때 자원 정리를 하고 싶다
- 세션이 생성/종료될 때 로그를 남기고 싶다
이런 “이벤트 기반 실행”을 위해 서블릿 API는 리스너(Listener)를 제공한다.
리스너는 “옵저버 패턴” 형태이다
리스너는 감시 대상(이벤트)이 있고,
이벤트가 발생하면 리스너가 자동으로 호출되는 구조이다.
즉 개발자는
- “언제 실행될지”를 직접 호출로 제어하는 게 아니라
- “이 이벤트가 발생하면 이 코드를 실행해라”를 등록한다
이게 리스너의 핵심이다.
// ================================
// [Listener 기본 형태] 애플리케이션 시작/종료 시점에 자동 실행
// - @WebListener + ServletContextListener
// ================================
@WebListener
public class AppInitListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 웹 애플리케이션 시작 시 1번 실행
ServletContext app = sce.getServletContext();
// 애플리케이션 공용 객체 등록 (Application Scope)
app.setAttribute("appName", "W2");
System.out.println("[Listener] contextInitialized: appName set");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 웹 애플리케이션 종료 시 1번 실행
System.out.println("[Listener] contextDestroyed");
}
}
ServletContextListener: 애플리케이션 시작/종료 이벤트
가장 대표적인 리스너가 ServletContextListener이다.
- contextInitialized() : 웹 애플리케이션 시작 시 1회 실행
- contextDestroyed() : 웹 애플리케이션 종료 시 1회 실행
즉 “서버가 뜰 때 / 내려갈 때” 실행되는 훅이다.
이 리스너가 왜 중요하냐면,
초기화 작업을 “한 곳에 모아서” 처리할 수 있기 때문이다.
ServletContext는 애플리케이션 공용 저장소(Application Scope)이다
`ServletContextListener`는 `ServletContextEvent`를 받는다.
여기서 getServletContext()로 ServletContext를 얻을 수 있다.
ServletContext는 한 문장으로 말하면 이거다.
현재 웹 애플리케이션 전체에서 공유하는 저장소
즉 여기다 값을 넣으면 모든 서블릿/JSP가 공유해서 볼 수 있다.
예:
- app.setAttribute("appName", "W2");
그러면 JSP에서는 EL로 이렇게 읽을 수 있다.
- ${appName}
- ${applicationScope.appName}
이게 application scope이다.
리스너를 쓰는 대표적인 이유: “초기화”를 한 번에
웹 애플리케이션은 보통 시작할 때 준비해야 하는 것들이 있다.
예:
- DB 커넥션 풀 초기화
- 서비스 객체 생성 및 등록
- 공용 설정값 로딩
- 공용 리소스 캐싱
이걸 각 컨트롤러에서 매번 만들면
- 중복 생성 문제가 생기고
- 관리가 어렵고
- 시작 시점 제어도 힘들어진다
그래서 리스너에서 한 번만 생성해서 ServletContext에 등록해두고
컨트롤러가 가져다 쓰는 구조가 가능해진다.
(나중에 스프링이 이런 역할을 더 체계적으로 해준다)
@WebListener로 등록한다
리스너는 컨테이너가 알아서 실행해야 하므로 등록이 필요하다.
요즘은 보통 어노테이션으로 등록한다.
- @WebListener
이 어노테이션이 붙어 있으면 톰캣이 시작할 때 리스너를 인식하고
해당 이벤트 시점에 자동 실행한다.
핵심 정리
- 리스너는 특정 이벤트 시점에 자동 실행되는 훅이다
- 필터가 “요청마다 실행”이라면, 리스너는 “시작/종료 같은 이벤트에 실행”이다
- ServletContextListener는 애플리케이션 시작/종료 시점에 실행된다
- ServletContext는 애플리케이션 공용 저장소(Application Scope)이다
- 초기화 작업(DB 풀, 공용 객체 준비 등)을 리스너에서 한 번에 처리할 수 있다
'Web > Web Basics' 카테고리의 다른 글
| [상태 유지와 공통 처리] 2. JDBC란? (0) | 2026.03.30 |
|---|---|
| [데이터 처리와 DB연동] 1. DTO / VO(Entity) / DAO / Service는 왜 나누는가? (0) | 2026.03.30 |
| [상태 유지와 공통 처리] 4. 필터(Filter)란? (0) | 2026.03.30 |
| [상태 유지와 공통 처리] 3. SESSIONID이란? (0) | 2026.03.30 |
| [상태 유지와 공통처리] 2-1. req.getSession()과 JSESSIONID, HttpSession (0) | 2026.03.30 |