코딩하는토끼 2021. 12. 4. 00:23

클라이언트에서 요청이 와야 servlet / jsp 가 실행되는데, 요청이 오기 전에 어떤 작업을 미리 하고싶다면

→ Servlet Context Listener

application 이 실행될 때 Servlet Context Listener 가 가지고있는 특정 메소드를 실행시킴

어떤 servlet / jsp 보다 먼저 실행된다는 보장이 있음

어플리케이션을 실행하면 실행됨

필터는 요청이 와야 실행되지만 리스너는 요청과 무관 (경로지정도 하지 않음)

 

교재 20chapter

listener01 패키지 생성 - 패키지 우클릭 - new - Listener 생성

Class name: AppListener01

Lifecycle 선택

 

다음과 같이 작성된 채로 생성됨

package listener01;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * Application Lifecycle Listener implementation class AppListener01
 *
 */
@WebListener
public class AppListener01 implements ServletContextListener {

    /**
     * Default constructor. 
     */
    public AppListener01() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    }
	
}

@WebListener 붙어있으면 tomcat이 확인하여 적절히 실행시켜줌

AppListener01 implements ServletContextListener 

- ServletContextListener 인터페이스를 구현하도록 만듦

메소드

1)contextDestroyed : tomcat 에 의해 종료될 때 실행됨

- web application 종료 직전에 실행되는 메소드

- 해당 web application 종료 전에 실행해야 할 작업을 명시하여 이용할 수 있음 (ex. 백업)

2)contextInitialized : tomcat 에 의해 실행 되자마자 (준비가 되자마자) 실행됨

- web application 시작 시 한번 생성되는 ServletContext 생성 직후 호출되어 실행됨

- 해당 web application 초기화 관련 작업에 이용할 수 있음

 

AppListener01

package listener01;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * Application Lifecycle Listener implementation class AppListener01
 *
 */
@WebListener
public class AppListener01 implements ServletContextListener {

    /**
     * Default constructor. 
     */
    public AppListener01() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("어플리케이션 종료됨!! 리스너1 작동!!!!");
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("어플리케이션 실행됨. 리스너1 작동!!!!");
    }
	
}

 

contextDestroyed 메소드 안에 "어플리케이션 종료됨!! 리스너1 작동!!!!" 출력되도록 작성

contextInitialized 메소드 안에 "어플리케이션 실행됨. 리스너1 작동!!!!" 출력되도록 작성

server (tomcat) 를 restart 하여 로그가 출력되는지 확인 (요청없이 서버 시작만 해도 실행됨) / 종료할 때는 역순

 

AppListener02

package listener01;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * Application Lifecycle Listener implementation class AppListener02
 *
 */
@WebListener
public class AppListener02 implements ServletContextListener {

    /**
     * Default constructor. 
     */
    public AppListener02() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("어플리케이션 종료됨!!! 리스너2 일함!!!!!");
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("어플리케이션 실행됨!! 리스너2 일함!!!!!!!");
    }
	
}

1, 2 둘다 실행됨~!

 

AppListener03

package listener01;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * Application Lifecycle Listener implementation class AppListener03
 *
 */
// @WebListener
public class AppListener03 implements ServletContextListener {

    /**
     * Default constructor. 
     */
    public AppListener03() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("어플리케이션 종료됨!! 리스너 3번 동작!!");
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("어플리케이션 실행됨!! 리스너3번 동작!!!");
    }
	
}

이번에는 web.xml 을 이용하여 listener 등록해보기

web.xml 사용하려면 @WebListener 주석처리 해야 함 (삭제)

* contextInitialized() 메소드는 등록된 순서대로 실행됨 ↔ contextDestroyed() 메소드는 등록된 반대 순서로 실행됨

 

web.xml

	<listener>
		<listener-class>listener01.AppListener03</listener-class>
	</listener>

(필터와는 다르게 이렇게 간단히 작성) 패키지명.Listener이름

* web.xml 의 listener 가 웹어노테이션보다 빨리 실행됨 (웹어노테이션의 순서는 보장되지 않음)

 

 

AppListener04

package listener01;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * Application Lifecycle Listener implementation class AppListener04
 *
 */
// @WebListener
public class AppListener04 implements ServletContextListener {

    /**
     * Default constructor. 
     */
    public AppListener04() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("애플리케이션 종료됨! 4번 리스너 실행");
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    	System.out.println("애플리케이션 실행됨!4번 리스너 실행");
    }
	
}

server (tomcat) 을 restart 해서 로그가 출력되는지 확인

web.xml 사용

	<listener>
		<listener-class>listener01.AppListener03</listener-class>
	</listener>
	<listener>
		<listener-class>listener01.AppListener04</listener-class>
	</listener>

 


1: @WebListener 

2: @WebListener

3: web.xml - 첫번째로 작성

4: web.xml - 두번째로 작성

실행 시, 3 - 4 - 1 - 2

종료 시 (역순), 2 - 1 - 4 - 3


AppListener05

package listener01;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
 * Application Lifecycle Listener implementation class AppListener05
 *
 */
// @WebListener
public class AppListener05 implements ServletContextListener {

    /**
     * Default constructor. 
     */
    public AppListener05() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent sce)  { 
         // TODO Auto-generated method stub
    }

	/**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent sce)  { 
    	ServletContext application = sce.getServletContext();
    	application.setAttribute("appAttr1", "appVal1");
    	application.setAttribute("appAttr2", "appVal2");
    	
    	// context path를 application attribute에 추가
    	String contextPath = application.getContextPath();
    	application.setAttribute("appRoot", contextPath);
    }
	
}

contextInitialized 메소드에 코드 작성

application.setAttribute 로

appVal1 은 appAttr1 에 저장, appVal2 는 appAttr2 에 저장하여 전달

// context path 를 application attribute 에 추가

application.getContextPath() 로 전달받아서 문자열 contextPath 에 저장

application.setAttribute 로 방금 받은 contextPath 를 appRoot 에 저장

 

01listener.jsp

이번엔 webapp > WEB-INF > view 폴더 말고 그냥 webapp 폴더 안에

15listener 폴더 만들고 01listener.jsp 파일 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<link rel="stylesheet" href="<%= request.getContextPath() %>/resource/css/icon/css/all.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">

<title>Insert title here</title>
</head>
<body>
  \${appAttr1 } : ${appAttr1 } <br>
  \${appAttr2 } : ${appAttr2 } <br> 
  <%-- appAttr2 attribute를 application 영역에 추가하는 코드를
    AppListener05의 contextInitialized 메소드에 작성
   --%>
   
   <hr>
   \${pageCotext.request.contextPath } : ${pageContext.request.contextPath } <br>
   \${appRoot } : ${appRoot } <br>
   <%= request.getContextPath() %> <br>
   
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
</body>
</html>

( \ 백슬래시 쓰면 el 적용 안된다고 했던 것 같은데.. )

아무튼 ${appAttr1 }, ${appAttr2 }, ${pageContext.request.contextPath }, ${appRoot } 출력

표현식으로 또 뭔가 전달받아서 출력

 

web.xml

	<listener>
		<listener-class>listener01.AppListener04</listener-class>
	</listener>
	<listener>
		<listener-class>listener01.AppListener03</listener-class>
	</listener>
	<listener>
		<listener-class>listener01.AppListener05</listener-class>
	</listener>

 

★ 01listener.jsp 실행 시 이것이 요청되기 전에 (서버가 실행될 때), AppListener05 리스너의 contextInitialized 메소드가 실행됨

→ appVal1 은 appAttr1 에 저장, appVal2 는 appAttr2 에 저장하여 01listener.jsp 에서 el 로 사용가능했음