ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 웹개발 - 서블릿 생명주기 Servlet Life Cycle
    비전공자 공부일기/:: WEB & Front-End 2019. 7. 2. 09:51

    2019. 07. 01 필기

     

    서블릿 생명주기란?

    서블릿은 클라이언트로부터 요청을 받으면 요청에 의해 WAS(Web Application Server)의 컨테이너가 인스턴스를 생성하여 요청 처리 후 응답한다.
    => WAS의 컨테이너가 서블릿 인스턴스의 생성, 사용(=메소드 호출), 소멸에 대한 전반적인 관리를 담당한다.
    => 만약 기존에 생성된 서블릿 인스턴스가 이미 존재할 경우 새로 인스턴스를 생성하지 않는다
    => WAS가 종료되면 컨테이너가 서블릿 인스턴스를 소멸시킨다
    => 이 때, 서블릿 인스턴스의 생성~사용~소멸 과정을 '생명주기(=Life Cycle)'이라고 한다.

     

    서블릿의 생명주기를 확인해보는 예시

    @WebServlet(name = "LifeCycleServlet", urlPatterns = { "/life.itwill" })
    public class LifeCycleServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
    
    	// 1) 기본 생성자
    	public LifeCycleServlet() {
    		System.out.println("# LifeCycleServlet 클래스의 기본 생성자");
    	}
    	
        // 2) init()으로 초기화 --- 생성자 대신 초기화 작업
    	@Override
    	public void init(ServletConfig config) throws ServletException {
    		config.getInitParameter("name");
    		System.out.println("# LifeCycleServlet 클래스의 init() 메소드 호출");
    	}
    	
    	// 3) service()
    	protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    		System.out.println("# LifeCycleServlet 클래스의 service() 메소드 호출");
    		
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out=response.getWriter();
    		
    		out.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("<title>Servlet</title>");
    		out.println("<body>");
    		out.println("<h1>서블릿(Servlet)</h1>");
    		out.println("<hr>");
    		out.println("<p>Hello, Servlet!!!</p>");
    		out.println("</body>");
    		out.println("</html>");
    	}
    
    	// 4) destroy() 오버라이드
    	@Override
    	public void destroy() {
    		System.out.println("# LifeCycleServlet 클래스의 destroy() 메소드 호출");
    	}
    	
    }
    

    1) 생성자 : 인스턴스를 생성하는 특별한 메소드 
    => 인스턴스 생성시 생성자를 한 번만 호출 : 초기화 작업(필드 초기값 부여) 
    => 서블릿은 인스턴스를 딱 한개만 생성한다(싱글톤) 따라서 생성자도 딱 한개만 필요

    ----- 자바 공부 초기부터 초기화에 대한 이해가 무척 어려웠는데, 다음과 같이 이해하기로 했다.
    달리기 경주가 열렸다. 선수들도, 관중들도 모두 경주는 출발선에서 시작한다는 건 안다. 하지만 안내원이 제때 출발선이 어디인지 안내하고 세워주지 않으면 우왕좌왕 할 것이다. 초기화는 바로 출발선으로 안내해주는 작업이다. 이렇게 이해했더니 마음이 편해졌다.

    2) init( ) : 서블릿 인스턴스 생성 후 가장 먼저 자동호출되는 메소드 --- 역시 한 번만 호출됨
    => 생성자 대신 init() 메소드로 초기화 작업을 하는 이유는 ServletConfig 인스턴스를 제공받아 사용하기 때문
    --- ServletConfig란? : web.xml 파일에 존재하는 정보를 제공받는 기능이 담긴 인스턴스
    --- 이클립스에서 init을 치고 ctrl + space를 누르면 오버라이드 가능한 메소드가 두 가지가 뜨는데, 반드시 ServletConfig 파라미터를 가진 것으로 오버라이드

    3) service( ) : 클라이언트의 요청마다 컨테이너에 의해 자동 호출되는 메소드
    => 요청처리 후 응답문서를 생성하여 클라이언트에게 제공하는 메소드
    => doGet() 및 doPost() 메소드도 유사한 작업을 수행하는 메소드
    => 메소드 선언되어 있지 않은 경우 클라이언트에게 405코드 전달

    4) destroy( ) : 서블릿 인스턴스가 소멸되기 전에 한 번만 자동 호출되는 메소드
    --- 실제로 하는 역할은 없다. 따라서 굳이 오버라이드 하지 않아도 되지만 여기서는 예시를 위해 오버라이드

     

    서블릿 인스턴스의 사용을 확인해볼 수 있는 메소드 예시

    //클라이언트의 요청마다 서블릿 요청횟수를 클라이언트에게 제공하는 웹 어플리케이션
    @WebServlet("/count.itwill")
    public class CountServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
    	
    	/*
    	 * //서블릿의 요청 회수를 누적 저장하기 위한 필드 선언 // => WAS 종료시 인스턴스 소멸 - 필드 소멸 >> 계속 남아있게 하려면?
    	 * 어딘가에 저장해주어야 한다. // >> 어디에? 파일에
    	 *  private int cnt; // 필드는 자동 초기화되기 때문에 =0 으로 초기화해주지 않아도 된다.
    	 */	
    	
    	private int newcount;
    	
    	
    	//카운터 파일의 절대경로를 저장하기 위한 필드
    	private String counterFilePath;
    
    	//카운터 파일에 저장된 정보를 읽어 필드에 저장
    	// => 카운터 파일에 없는 경우는 필드에 초기값으로 0 저장
    	@Override
    	public void init(ServletConfig config) throws ServletException {
    		
    		//카운터 파일의 절대경로를 반환받아 저장
    		// 컨텍스트의 위치, 서버에 올리는 위치는 각기 다르기 때문에 절대경로는 위험  >> 반드시 컨텍스트에게 자원경로를 달라고 해야함
    		// >> request한테 없으면 config를 사용하면 절대경로 사용 가능
    		counterFilePath=config.getServletContext().getRealPath("/WEB-INF/counter.txt");
    		/* System.out.println("counterFilePath = "+counterFilePath); */
    
    		
    		try {
    			//카운터 파일에 대한 입력스트림을 생성하여 저장
    			ObjectInputStream ois=new ObjectInputStream(new FileInputStream(counterFilePath));
    
    			//파일 입력스트림을 이용하여 카운터 정보(서블릿 요청횟수)를 반환받아 필드에 저장
    			newcount=(Integer)ois.readObject();
    			
    			//파일 입력스트림 제거
    			ois.close();
    			
    		} catch (Exception e) {
    			newcount=0;
    		}
    	}
    
    	
    	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out=response.getWriter();
    		
    		//서블릿 요청 횟수를 누적하기 위한 변수
    		// => 메소드가 종료되면 자동 소멸되는 지역변수 - 변수값 유지 불가능
    		/* int count=0; */
    		//서블릿 요청 횟수 누적
    		newcount++;
    		/* cnt++; */
    		
    		out.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("<title>Servlet</title>");
    		out.println("<body>");
    		out.println("<h1>서블릿 카운트</h1>");
    		out.println("<hr>");
    		/* out.println("<p>잘못된 서블릿 요청횟수 = "+count+"</p>"); */
    		/* out.println("<p>실제 서블릿 요청횟수 = "+cnt+"</p>"); */
    		out.println("<p>서블릿 요청횟수 = "+newcount+"</p>");
    		out.println("</body>");
    		out.println("</html>");
    	}
    	
    	
    		
    	//필드값(서블릿 요청횟수)을 카운터 파일에 저장할 수 있도록 만듬
    	// => 카운터 파일이 존재하지 않는 경우 파일 생성하여 필드값 저장
    	@Override
    	public void destroy() {
    		try {
    			//카운터 파일에 대한 출력스트림을 생성하여 저장
    			ObjectOutputStream oos= new ObjectOutputStream
    					(new FileOutputStream(counterFilePath));
    			
    			//파일 출력스트림을 이용하여 카운터 정보(서블릿 요청 횟수)를 반환받아 필드에 저장
    			oos.writeObject(newcount);
    			
    			//파일 출력스트림 제거
    			oos.close();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    ==> 위 예시를 통해, 서블릿 인스턴스가 사용되는 횟수를 확인해볼 수 있다.

    댓글

coding wanee