 |
서블릿 Listener가 정확히 무슨 역할을 하며, 어떤 곳에 활용할 수 있을지 찾아보다가 서블릿의 기초인 Life Cycle 문서를 보게 되었네요. 그 동안 너무 기초에 소홀한 느낌이 들어서 다시 한번 되짚어 보고 있습니다. 처음에 서블릿을 배울 때는 이해하지 못했던 부분들이 지금 다시 보니까 쉽게 이해가 되는군요. 그래서 가끔씩 과거에 읽었던 책이나 문서들을 다시금 되짚어 볼 필요가 있는거 같습니다.
이러다가 오늘 중으로 서블릿 Listener가 뭐하는 놈인지 찾을 수나 있으려는지..뭐 못찾으면 내일도 있으니까요..h2. |
온라인 문서
Servlet Life Cycle
문서를 참고하면 Servlet의 Life Cycle에 대하여 깊이 있게 이해할 수 있다.
Introduction
서블릿의 Life Cycle은 Container에 의하여 관리된다. 모든 서블릿이 사용되기 위해서는 web.xml에 Mapping하여 사용하는 것이 일반적이다. 만약 Mapping된 서블릿에 요청을 보낸다면 다음과 같은 과정을 통하여 서블릿이 실행된다.
- 서블릿 인스턴스가 존재하지 않는다면..
- 클래스 로더는 서블릿 클래스를 로드한다.
- 서블릿 클래스의 인스턴스를 생성한다.
- 서블릿 클래스의 init() 메써드를 호출함으로서 초기화를 진행한다. 서블릿의 초기화 과정에 대해서는 Initializing a Servlet
문서를 참고하기 바란다.
Handling Servlet Life Cycle Events
아직 감은 잘 오지 않지만 암튼 나름대로 정리하자면, Servlet의 Life Cycle 상에서 Event가 발생할 경우 Event 성격에 따른 Listener를 만들어 등록했다가 특정 작업을 할 수 있도록 하는 것으로 이해한다.
javax.servlet.ServletContextListener를 상속하는 Listener는 Container가 시작할 때와 종료할 때 원하는 작업을 수행할 수 있다. ServletContext에 Servlet Life Cycle
의 예제를 보면서 이해하면 다음과 같다.
import database.BookDB;
import javax.servlet.*;
import util.Counter;
public final class ContextListener
implements ServletContextListener {
private ServletContext context = null;
public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();
try {
BookDB bookDB = new BookDB();
context.setAttribute("bookDB", bookDB);
} catch (Exception ex) {
System.out.println(
"Couldn't create database: "
+ ex.getMessage());
}
Counter counter = new Counter();
context.setAttribute("hitCounter", counter);
context.log("Created hitCounter"
+ counter.getCounter());
counter = new Counter();
context.setAttribute("orderCounter", counter);
context.log("Created orderCounter"
+ counter.getCounter());
}
public void contextDestroyed(ServletContextEvent event) {
context = event.getServletContext();
BookDB bookDB = context.getAttribute(
"bookDB");
bookDB.remove();
context.removeAttribute("bookDB");
context.removeAttribute("hitCounter");
context.removeAttribute("orderCounter");
}
}
Container가 시작할 때 Application 전체에서 사용할 수 있는 전역변수처럼 인스턴스를 생성하여 ServletContext로 접근할 수 있는 어느 곳에서나 접근이 가능하도록 구현하고 있다. 즉, Container가 시작할 때 한번만 초기화하고 다음 요청부터 이용할 필요가 있는 기능들이 있다면 이와 같은 기능을 사용하면 좋을 것으로 생각한다.
web.xml에 위 Listener를 등록하는 과정은 다음과 같다.
<listener>
<listener-class>listeners.ContextListener</listener-class>
</listener>
위에서 초기화된 인스턴스를 이용하는 예제는 다음과 같다.
public final class HitCounterFilter implements Filter {
private FilterConfig filterConfig = null;
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
...
StringWriter sw = new StringWriter();
PrintWriter writer = new PrintWriter(sw);
ServletContext context = filterConfig.
getServletContext();
Counter counter = (Counter)context.
getAttribute("hitCounter");
...
writer.println("The number of hits is: " +
counter.incCounter());
...
context.log(sw.getBuffer().toString());
...
}
}
Servlet Filter는 특정 애플리케이션의 모든 요청을 처리하는 것이 가능하다. 위와 같이 Servlet Filter로 진입하는 모든 요청에 대하여 HitCount를 계산하는 것이 가능하다.
 |
Spring 프레임워크가 ServletContextListener를 이용해서 XML에 저장되어 있는 내용을 초기화한다. Spring 프레임워크의 초기화 과정을 이해한다면 Listener를 이해하는데 많은 도움이 될 것으로 생각한다. 조만간 Spring 프레임워크도 이해할겸 한번 분석해 보자. 이것도 재밌는 작업이 되겠군. |