발표자료 4 ~ 7 단원 내용 중 ...

2. Servlet 따라가보기 이어서!

발표자료보다 내용을 더 추가해서 PPT가...없을 수 있다....ㅎ..

 

[이전글]

2020/11/05 - [IT/Servlet & JSP] - [Servlet & JSP] 2. Servlet 따라가보기 

 

[Servlet & JSP] 2. Servlet 따라가보기

발표자료 4 ~ 7 단원 내용 중 ... Servlet 최초 클라이언트의 요청이 있기 전에 서블릿은 항상 로딩되고 초기화됩니다. 로딩되는 시기는 컨테이너 시작 (즉, 톰캣이 실행될 때) 이루어집니다. 그리고

song-yujin.tistory.com

 

속성과 리스너


이제 속성 내용은 앞에서 이야기한 ServletConfig ServletContext내용입니다.

 

 

 

앞에서 이야기한 ServletConfig 가장 역할은 서블릿 초기화 파라미터에 접근할 있는 능력이 있다는 것입니다.

ServletConfig 값을 설정하기 위한 곳이 코드 보이는 것처럼 DD(배포 서술자)이고, 하나의 Servlet에서 계속적으로 읽어와서 사용하고자하는 용도보다는 처음에 Servlet 로딩시 읽어와서 계속 사용하고자 하는 의미가 큽니다.

 

서블릿의 설정이기 때문에 servlet안에다가 작성을 해줘야합니다. 그리고 서블릿 코드에서는 GetServletConfig() 메소드의 리턴값이 servletConfig여서 servletConfig getInitParameter()메소드를 접근하여 사용할 있습니다.

 

 

 

그런데 화면을 나타내는 JSP페이지에서도 서블릿의 초기화 파라미터 값을 읽으려면, 이것은 그대로 서블릿의 설정이기 때문에 가지 작업을 해야합니다.

그리고 만약에 이메일 정보를 모든 애플리케이션에서 공유해야하고, 요청할 때마다 달라지지 않을 , 서블릿에만 적용되는 초기화 파라미터 말고 애플리케이션 적용되는 것이 없나? 대한 한계가 나왔습니다.

 

 

 

한계의 답이 컨텍스트 초기화 파라미터입니다.

이것은 서블릿 초기화 파라미터와 동일하지만, 컨텍스트 초기화 파라미터는 특정 하나의 서블릿만 사용하는 것이 아니라 모든 애플리케이션에서 이용할 있다는 차이가 있습니다. 애플리케이션에 있는 모든 JSP, 서블릿에서 별다른 코딩 없이도 컨텍스트 초기화 파라미터 정보에 접근할 있으며, 모든 서블릿의 DD 수정하는 따위는 하지 않아도 됩니다.

 

코드를 보면 servletConfig 거의 비슷한데 다른점은 servlet 안에다가 작성하면 안되는 부분, 그리고 getServletContext()라는 것입니다.

 

 

 

표는 ServletConfig와 ServletContext 비교하여 정리한 표입니다. 

 

ServletContext에 대해서 더 정리를 하겠습니다.

ServletContext는 JSP나 서블릿을 컨테이너 또는 다른 웹 애플리케이션과 연결하는 끈이라고 할 수 있습니다.

 

 

컨텍스트 파라미터의 한계


컨텍스트 파라미터에는 String 밖에 저장할 수 없습니다. 

초기화 파라미터로 Dog라는 객체를 저장하고 싶을 때나 애플리케이션에 있는 모든 서블릿이 데이터베이스 Connection객체를 공유하고 싶을 때는 어떻게 하지? 라는 한계가 나왔습니다. 

 

가장 일반적인 방법은 "컨텍스트 파라미터에 DataSource 검색명(lookup name)를 저장하는 것입니다.

 

그런데 이것을 또 누가 하느냐? 이야기가 나올 수 있습니다.

서블릿에서 검색명으로 실제 DataSource 객체를 찾아서, 이 객체를 속성에 묶어두면 되지 않을까? 싶지만 안됩니다. 

서블릿 코드 안에다가 넣을 수 없는 이유는 어떤 서블릿이 가장 먼저 호출될지 모르기 때문입니다.

 

 

 

 

리스너


이것에 대한 답은 리스너입니다. 

 

웹 애플리케이션에도 main()처럼 제일 먼저 실행되는 메소드, 어떤 서블릿이나 JSP보다도 먼저 실행되어야 하는 코드를 작성할 메소드!

이것이 바로 리스너입니다.

 

즉, 컨텍스트 초기화 이벤트에 리스닝하는 것입니다. 이를 이용하면 컨텍스트 초기화 파라미터를 읽은 다음, 애플리케이션이 클라이언트에게 서비스하기 전에 특정 코드를 실행할 수 있습니다. 

 

이것은 서블릿이나 JSP가 아닌 다른 자바 객체가 해주는데 "ServletContextListener"입니다.

ServletContextListener의 목적은 애플리케이션 초기화입니다.  

 

이 클래스는 ServletContext 이벤트(초기화(생성)와 소멸)에 귀 기울이고 있어야 합니다. 

javax.servlet.ServletContextListener 인터페이스를 구현하면 이 클래스를 만들 수 있습니다. 

 

빨간색 표시로 되어있는 부분은 구현한 클래스가 이러한 기능들을 가져야 합니다.

 

 

ServletContextListener 사용하기 


지금부터 ServletContextListener를 만들고 실행시키는 테스트를 해서 어떻게 동작하는지 보겠습니다. 

 

이 예제에서는 String 초기화 파라미터를 실제 객체(Dog)로 전환할 것입니다.

 

<시나리오>

  1. 리스너는 컨텍스트 초기화 파라미터에서 개의 품종을 확인한 다음, 이 값을 Dog 객체 생성자 인자로 사용하여 Dog를 생성
  2. 리스너는 Dog 객체를 ServletContext 속성에 묶어 두는 작업

그러면 서블릿이 이를 끄집어 낼 수 있습니다. 

이렇게 하면 서블릿이 애플리케이션 객체(여기서는 Dog)를 공유할 수 있습니다. 이제 서블릿이 컨텍스트 파라미터를 읽을 필요가 없습니다. 

 

초기화 파라미터로 객체를 생성할 수 있다는 것과 이 객체를 모든 애플리케이션에서 공유할 수 있다는 것이 중요합니다. 

 

 

<Dog 예제>

  1. 리스너는 ServletContextEvent에서 ServletContext의 참조를 얻습니다.
  2. 리스너는 ServletContext에서 컨텍스트 초기화 파라미터 품종(breed)이 무엇인지 값을 읽습니다. 리턴되는 값은 품종이 무엇인가 하는 String입니다.
  3. 리스너는 품종 String으로 Dog 생성자를 호출합니다. 
  4. 리스너는 ServletContext의 속성(Attribute)에 생성한 Dog를 물려 놓습니다.
  5. 테스트 서블릿에서 ServletContext에 물려 있는 Dog 객체를 끄집어 내어, 품종이 무엇인지 getBreed() 메소드를 호출하여 확인합니다. 

따라서 정리를 하면,

1. ServletContext 이벤트를 리스닝하기 위해서는 ServletContextListener 인터페이스를 구현

2. 컴파일된 파일을 WEB-INF/classes 디렉토리에 배포

3. 배포 서술자 web.xml에 <listener> 항목을 추가하여 컨테이너에게 알림

 

 

 

ServletContextListener 튜토리얼


3개의 클래스와 하나의 DD가 필요합니다.

 

  1. MyServletContextListener.java (The ServletContextListener) : 컨텍스트 초기화 파라미터를 읽어, Dog 객체를 생성하고 이를 컨텍스트 속성에 묶음
  2. Dog.java (속성 클래스) : 평범한 자바 객체, ServletContextListener에서 생성되어 속성값이 됨. ServletContext의 속성에 묶어 두면, 나중에 서블릿이 꺼내 씀
  3. ListenerTester.java (서블릿) : HttpServlet 클래스를 상속함. 컨테스트에서 Dog 객체를 끄집어 내어 getBreed() 메소드를 호출하여 이 내용을 Response에 출력할 것.
  4. web.xml (배포 서술자) : 컨테이너한테 리스너를 만들었음을 알려줄 때. 

 

 

1. MyServletContextListener 작성

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

public class MyServletContextListener implements ServletContextListener {

  public void contextInitialized(ServletContextEvent event) {

    ServletContext sc = event.getServletContext();  // event에게 servletContext 요구
    String dogBreed = sc.getInitParameter("breed");   //컨텍스트에서 초기화 파라미터 읽음
    Dog d = new Dog(dogBreed);   //dog 객체 생성
    sc.setAttribute("dog", d);    //컨텍스트 속성에 이름/객체의 쌍으로 묶어 놓음
  }

  public void contextDestroyed(ServletContextEvent event) {

  }

}

컨텍스트 초기화 파라미터에서 개의 품종이 무엇인지 확인하여, 해당 품종의 Dog 객체를 생성한 다음, 이 객체를 컨텍스트 속성으로 묶어 놓은 것입니다. 

 

 

2. Dog 클래스 작성

public class Dog {

  private String breed;

  public Dog(String breed) {

    this.breed = breed;
  }

  public String getBreed() {

    return breed;
  }
}

컨텍스트 초기화 파라미터로 생성한 다음, ServletContext에 이 클래스를 속성으로 저장할 것입니다. 

 

 

3. ListenerTester 작성

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ListenerTester
 */
@WebServlet("/ListenerTester")
public class ListenerTester extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ListenerTester() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

	  response.setContentType("text/html");
	  PrintWriter out = response.getWriter();
	  
	  out.println("test context attributes set by listener<br>");
	  
	  out.println("<br>");
	  
	  Dog dog = (Dog) getServletContext().getAttribute("dog");   //리스너가 제대로 작동하지 않았다면, NullPointException 예외를 만날 것임.
	  
	  out.println("Dog's breed is: " + dog.getBreed());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

이 클래스는 ServletContextListener를 테스트하기 위한 것입니다. 제대로 작동한다면, 서블릿의 doGet()을 실행할 경우 Dog 객체가 서블릿 컨텍스트 안에 기다리고 있습니다. 

 

 

3. ListenerTester 작성

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>Project2</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>

  <context-param>
  	<param-name>breed</param-name>
  	<param-value>Great Dane</param-value>
  </context-param>
  
  <listener>
  	<listener-class>
  		MyServletContextListener
  	</listener-class>
  </listener>
</web-app>

 

'IT > Servlet & JSP' 카테고리의 다른 글

[Mini_WAS] WAS만들기 - 중간점검  (0) 2020.12.02
[Servlet & JSP] 2. Servlet 따라가보기  (0) 2020.11.05

+ Recent posts