본문 바로가기

Spring/Spring MVC

(SERVLET) 서블릿 리스너와 서블릿 필터

서블릿 리스너

: 서블릿 컨테이너에서 발생하는 이벤트 (lifecycle의 변화, session의 변화, attribute의 변화...)에 특정한 코드를 실행해야 할 때 사용

 

언제 사용되는가?

  • 서블릿 컨테이너 구동 시 데이터베이스 커넥션을 맺어놓고 해당 커넥션을 서블릿 애플리케이션에서 만든 여러 가지 서블릿에 제공하는 경우 (참고로 서블릿은 여러 개 생성이 가능하다.)
  • 서블릿 콘텍스트 내부의 서블릿 애트리뷰트에 접근하여 DB 커넥션을 꺼내 사용하는 경우
  • 서블릿 컨테이너 종료 시 리스너를 활용하여 초기에 만들어 두었던 DB 커넥션을 정리하는 경우
    • 서블릿 콘텍스트 수준의 이벤트

      • 콘텍스트 라이프사이클 이벤트

      • 콘텍스트 애트리뷰트 변경 이벤트

    • 세션 수준의 이벤트

      • 세션 라이프사이클 이벤트

      • 세션 애트리뷰트 변경 이벤트

서블릿 필터

: 요청이 들어왔을 때 doGet 혹은 doPost로 가지만 이 과정에서 특정한 사전작업을 하고 싶은 경우에 사용

언제 사용되는가?

  • 들어온 요청을 서블릿으로 보내고, 또 서블릿이 작성한 응답을 클라이언트로 보내기 전에 특별한 처리가 필요한 경우에 사용할 수      있다.
  • 체인 형태의 구조

 

 

  • 동시 다발적으로 Servlet Container와 Servlet이 communication 하는 것이 아니라 chain 형태로 순차적으로 진행된다.
  • web.xml에 정의한 순서대로 진행된다.
  • 반드시 다음 chain으로 넘어가게 코드를 작성해야 된다.

 

 

 


서블릿 리스너 생성

Listener 생성

public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("Context Initialized");
        sce.getServletContext().setAttribute("name","choi");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Context Destroyed");
    }
}

web.xml Listener 경로 등록

  <listener>
    <listener-class>me.choi.MyListener</listener-class>
  </listener>

servlet에 등록하였던 Listener 호출

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");

        resp.getWriter().println("<html>");
        resp.getWriter().println("<head>");
        resp.getWriter().println("<body>");
        resp.getWriter().println("<h1>Hello," + getName() + "</h1>");
        resp.getWriter().println("</body>");
        resp.getWriter().println("</head>");
        resp.getWriter().println("</html>");
    }

    private Object getName() {
        return getServletContext().getAttribute("name");
    }

실행결과

 

실행 시

Connected to server
[2020-01-11 04:15:11,732] Artifact java-servlet-demo:war exploded: Artifact is being deployed, please wait...
Context Initialized
[2020-01-11 04:15:13,143] Artifact java-servlet-demo:war exploded: Artifact is deployed successfully
[2020-01-11 04:15:13,143] Artifact java-servlet-demo:war exploded: Deploy took 1,411 milliseconds
11-Jan-2020 16:15:21.344 정보 [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployDirectory 웹 애플리케이션 디렉토리 [/Users/junwoochoi/Downloads/apache-tomcat-9.0.30/webapps/manager]을(를) 배치합니다.
11-Jan-2020 16:15:21.399 정보 [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployDirectory 웹 애플리케이션 디렉토리 [/Users/junwoochoi/Downloads/apache-tomcat-9.0.30/webapps/manager]에 대한 배치가 [54] 밀리초에 완료되었습니다.
init
doGet
doGet

로그 메시지를 살펴보자면

서버가 연결되고 ServletContext가 실행되는 시점(초기화하는 시점)에 Listener가 실행됨을 볼 수 있다.

@Override
public void contextInitialized(ServletContextEvent sce) {
    System.out.println("Context Initialized");
    sce.getServletContext().setAttribute("name","choi");
}

 

종료 시

destroy
Context Destroyed
11-Jan-2020 16:19:26.335 정보 [main] org.apache.coyote.AbstractProtocol.stop 프로토콜 핸들러 ["http-nio-8080"]을(를) 중지시킵니다.
11-Jan-2020 16:19:26.338 정보 [main] org.apache.coyote.AbstractProtocol.stop 프로토콜 핸들러 ["ajp-nio-8009"]을(를) 중지시킵니다.
11-Jan-2020 16:19:26.342 정보 [main] org.apache.coyote.AbstractProtocol.destroy 프로토콜 핸들러 ["http-nio-8080"]을(를) 소멸시킵니다.
11-Jan-2020 16:19:26.343 정보 [main] org.apache.coyote.AbstractProtocol.destroy 프로토콜 핸들러 ["ajp-nio-8009"]을(를) 소멸시킵니다.
Disconnected from server

서블릿이 종료가 되고 ServletContext가 종료되며 마지막으로 서버가 끊기게 된다.


서블릿 필터 생성

Listener는 servletcontext에서 servlet로 가능 과정이다. (Listenr 이후의 작업)

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter Init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("Filter Destroy");
    }
}

web.xml 설정

  <filter>
    <filter-name>myfilter</filter-name>
    <filter-class>me.choi.MyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myfilter</filter-name>
    <servlet-name>hello</servlet-name>
  </filter-mapping>

실행결과 servletcontext를 초기화하고 servlet으로 가는 과정에서 Filter를 거친다는 것을 볼 수 있다.


코드 참조

https://github.com/mike6321/Spring/tree/master/SpringMVC/java-servlet-demo

 

mike6321/Spring

Contribute to mike6321/Spring development by creating an account on GitHub.

github.com