Servlet LifeCycle / load-on-startup

기록하는 용도·2022년 9월 26일
0

Servlet LifeCycle

Lifecycle(Callback) 메소드
– init()
– service()
– destroy()

웹 프로그램은 LifeCycle이라는 생명주기를 갖는다.
모든 jsp, servlet은 위의 세가지의 메소드들이 구현되어 표준화가 되어있다.


Servlet LifeCycle 구조

Servlet, jsp의 최상위 인터페이스 Servlet의 abstract method인
init() -> service() -> destroy() 가 있다.
이 세가지 라이프 사이클 메소드를 WAS (Web Container)가 호출하여 실행된다.




client browser가 request하면 was는 입장, 실행된 적이 있는지 묻는다.
처음이라면 NO의 루트를 따라가고, 처음이 아니라면 바로 service() 메소드로 간다.


init()

객체 생성 후 서블릿 초기화 작업을 위해 한 번 실행한다.

service()

client 요청시마다 실행하고 요청에 응답을 매번 수행한다.

destroy()

서비스 해제 직전에 한 번 실행한다.



LifeCycle 예제1

package step2;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LifeCycleServlet
 */
public class LifeCycleServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	
	/**
	 * 서블릿 생성자
	 */
	public LifeCycleServlet() { //public 지우면 500 내부 서버 오류
		super();
		System.out.println("LifeCycleServlet 생성자 실행 -> LifeCycleServlet 객체 생성");
	}
	/**
	 * 서블릿 객체 생성 후 필요한 초기화 작업을 위해 한 번 실행
	 */
	
	@Override
	public void init() throws ServletException {
		System.out.println("LifeCycleServlet init() 실행");
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	
	/**
	 * 클라이언트 요청시마다 매번 실행
	 * service 계열 메소드 : web container가 service()를 호출 -> 내부적으로 method 따라 doGet 또는 doPost가 실행
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			System.out.println("LifeCycleServlet service() => doGet()");
			response.setContentType("text/html;charset=utf-8");
			PrintWriter out = response.getWriter();
			out.print("<html>");
			out.print("<body bgcolor=yellow>");
			out.print("<h3>" + this.getServletName() + "LifeCycle Test </h3>");
			out.print("</body>");
			out.print("</html>");
			out.close();
	}
	/**
	 * 		서비스 종료 직전에 한번 호출
	 */
	@Override
	public void destroy() {
		System.out.println("LifeCycleServlet destroy()");
	}
}

객체 생성 -> init() 실행 -> service() 순으로 실행되었다.
이 때 화면을 계속 새로고침해 doGet() 메소드 즉, service() 메소드를 호출한다면
요청시마다 매번 실행되는 것을 볼 수 있다.이 서버를 종료시키면

destroy() 메소드를 실행하고 종료한 것을 알 수 있다.



LifeCycle 예제2

package step3;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LifeCycleCountServlet2
 */
public class LifeCycleCountServlet2 extends HttpServlet {
	private static final long serialVersionUID = 1L;
    private int count;
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LifeCycleCountServlet2() {
        super();
        System.out.println("LifeCycleCountServlet2 객체 생성 count :" + count++);
    }
    @Override
    public void init() throws ServletException {
    	super.init();
    	System.out.println("LifeCycleCountServlet2 init count : " + count++);
    }
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		out.print("<html>");
		out.print("<body bgcolor=yellow>");
		out.print("<h3>" + this.getServletName() + "</h3>");
		out.print("<h4>count:" + count++ + "</h4>");
		out.print("</body>");
		out.print("</html>");
		out.close();
	}//객체가 하나생성되어서 여러 클라이언트에 정보가 공유된다.
	//텍스트파일에 썼던 객체 생성한번되면 이느스턴스 변수 공간은 딱 하나 생성되고 힙영역에 인스턴스 하나만 있기때문에 동일한 카운트 값을 공유해서 누적시키고있다.

}

class 내에 private int 변수로 count를 선언했다.
0으로 초기화 될것이고, servlet의 생명주기는 객체 생성이 첫번째로

 public LifeCycleCountServlet2() {
        super();
        System.out.println("LifeCycleCountServlet2 객체 생성 count :" + count++);
    }

에서 0을 출력하지만 출력 이후에는 count는 1이 되었다.


public void init() throws ServletException {
    	super.init();
    	System.out.println("LifeCycleCountServlet2 init count : " + count++);
    }

servlet의 두번째 순서인 init() 메소드 내부이다.
객체 생성에서 count는 1이되어 1을 출력하고 이후에 count는 2가된다.


protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		out.print("<html>");
		out.print("<body bgcolor=yellow>");
		out.print("<h3>" + this.getServletName() + "</h3>");
		out.print("<h4>count:" + count++ + "</h4>");
		out.print("</body>");
		out.print("</html>");
		out.close();
	}

service() 메소드인 doGet() 메소드에서 화면은 2를 찍고 이후에 count는 3이 된다.
그리고 이 메소드를 새로고침에 계속해서 호출한다면 화면에는 ++1씩 된 count를 볼 수 있을것이다.



객체가 한개 생성되어 여러 클라이언트에 정보가 공유된다.
텍스트 파일에 썼던 객체 생성이 한 번 되면 인스턴스 변수 공간은 딱 하나 생성되고 힙 영역에 인스턴스 변수 하나만 있기 때문에 동일한 count 값을 공유해서 누적시키는 것이다.

첫 손님만이 이 과정을 겪는것인데 이 과정이 많다면 불리할 수 있다.
loadon startup 옵션을 통해서 xml이나 annotation에서 기본 lifecycle에서 제공했던 이 세가지 과정을 줄일 수 있다.
즉 어플리케이션이 실행되면 service()를 바로 실행 할 수 있도록 하는 것이다.

load-on-startup

<load-on-startup>1</load-on-startup>

WAS 시작 시에 미리 서블릿을 초기화 시킨다.
Servlet LifeCycle 특성상 클라이언트의 첫번째 요청시 서블릿 객체 생성, init() 실행 후 service 계열 메소드가 실행되어 클라이언트에게 응답된다.
이런 경우 첫번째 클라이언트의 요청에 대해서 응답이 느려질 경우를 대비해
WAS 시작 시점에 지정한 서블릿의 객체 생성과 init 즉 초기화 작업을 미리 수행하도록 XML : web.xml 또는 Annotation : @WebServlet 에서 load in startup 옵션을 지정할 수 있다.
was 시작시에 미리 로드시킨다.

@WebServlet(urlPatterns ="/AnnotationConfigLifeCycleServlet", loadOnStartup = 1)

annotation 기반으로 줄 수도 있다.

0개의 댓글