Lifecycle(Callback) 메소드
– init()
– service()
– destroy()
웹 프로그램은 LifeCycle이라는 생명주기를 갖는다.
모든 jsp, servlet은 위의 세가지의 메소드들이 구현되어 표준화가 되어있다.
Servlet, jsp의 최상위 인터페이스 Servlet의 abstract method인
init() -> service() -> destroy() 가 있다.
이 세가지 라이프 사이클 메소드를 WAS (Web Container)가 호출하여 실행된다.
client browser가 request하면 was는 입장, 실행된 적이 있는지 묻는다.
처음이라면 NO의 루트를 따라가고, 처음이 아니라면 바로 service() 메소드로 간다.
객체 생성 후 서블릿 초기화 작업을 위해 한 번 실행한다.
client 요청시마다 실행하고 요청에 응답을 매번 수행한다.
서비스 해제 직전에 한 번 실행한다.
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() 메소드를 실행하고 종료한 것을 알 수 있다.
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>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 기반으로 줄 수도 있다.