Servlet, Servlet Lifecycle

kimwoody·2021년 11월 16일
0

Java Web Programming

목록 보기
2/4

저번에 Web Server와 WAS를 구분하는 글을 올렸습니다.

Web Server는 정적 페이지를, WAS는 동적 페이지를 제공하는데 오늘은 WAS에서 동적 페이지를 제공하기 위해 사용하는 기술은 Servlet에 대해 포스팅하려고 합니다.

CGI? Servlet?

웹에서 동적인 서비스를 제공해주는 기술 중 CGI(Common Gateway Interface)라는 기술이 있었습니다.

CGI를 사용하면서 동적 페이지를 제공할 수 있었지만, CGI는 두가지의 문제점이 있습니다. 첫째, CGI는 쓰레드가 아닌 프로세스를 사용합니다.

그리고 두 번째 문제점, CGI는 같은 구현체를 사용해도 웹 요청을 받을때 마다 구현체가 계속 생긴다는 점입니다.

위의 그림을 보시면 프로세스를 사용하는 CGI는 여러게의 리퀘스트를 받으면 여러개의 프로세스를 만들게 되고, 같은 CGI 구현체들이 계속 생겨납니다. 그러면서 Proccessor load가 높아지는 것을 볼 수 있습니다. 이 문제점들을 보완해서 프로세스를 쓰레드로, 여러 구현체를 생성하는 방법에서 싱글톤 패턴 적용한 서블릿을 사용하게 됩니다.

위의 그림을 보시면 CGI에 비해서 Servlet의 Processor load가 낮은 것을 볼 수 있습니다.

서블릿(Servlet)은 무엇인가?

위에서 CGI와 서블릿을 비교해봤습니다. 이제는 서블릿에 대해 알아봅시다.

서블릿은 클라이언트의 요청에 따라 동적으로 컨텐츠를 만들 수 있는 기술이고 자바로 만들어집니다. 자바를 사용해서 서블릿을 만들게 되면 서블릿 관련 인터페이스들을 상속받아 구현합니다.

위 그림을 보면 서블릿의 상속 계층 구조를 알 수 있고, https://javaee.github.io/javaee-spec/javadocs/ 이 링크로 가시면 인터페이스와 추상 클래스들의 상속 관계와 메소드들도 확인할 수 있습니다.

서블릿의 특징

  • 서버에서 실행되는 자바 웹 기술
  • HTTP 요청에 동적으로 응답함
  • 자바 쓰레드를 사용하기때문에 효율적임
  • MVC 패턴에서 컨트롤러로 사용
  • 서블릿 컨테이너에서 서블릿 생명주기를 관리함

서블릿 생명주기(Servlet Lifecycle)

위에서 서블릿의 상속관계와 특징에 대해서 알아보았고, 지금은 서블릿의 생명주기에 대해 알아보겠습니다.

위 그림을 보시면 서블릿 계층구조의 최상위 인터페이스 Servlet은 init(), service(), destroy()라는 세 개의 생명주기 메소드를 갖고 있습니다.

단계메소드특징
초기화init()서블릿 요청시 맨 처음 한 번만 호출
작업수행service()서블릿 요청시 매 번 호출
HTTP 요청이 get인지 post인지 구분하여 doGet(), doPost() 등 do 메소드를 호출함
종료destroy()서블릿이 기능을 수행하고 서비스가 종료되기(WAS 중지) 직전에 호출

WAS 안에 있는 컨테이너는 서블릿의 생명주기를 관리하게 됩니다.

위의 각 생명주기 메소드들의 특징을 유념하면서 코드를 통해 실습해보겠습니다.

public class CountServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private String path = "C:\\kosta224\\iotest\\count";
    private int count;
    
    public CountServlet() {
        super();
        System.out.println("CountServlet 객체 생성");
    }
    
	@Override
	public void init() throws ServletException {
		File countFile = new File(path);
		if(countFile.isFile()) {
			try {
				DataInputStream dis = new DataInputStream(new FileInputStream(countFile));
				count = dis.readInt();
				dis.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		else {
			count++;
		}
		System.out.println("init() 실행");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("service() 실행");
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		
		out.println("<h3>CountServlet service 계열 method 실행");
		out.println(" 접속수:" + count + "</h3>");
		count++;
		
		out.close();
	}

	@Override
	public void destroy() {
		try {
			DataOutputStream dos = new DataOutputStream(new FileOutputStream(path));
			dos.writeInt(count);
			dos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("destroy 실행-조회수 백업");
	}

	
}

위 코드를 실행하게 되면 콘솔에는 "init() 실행", "service() 실행", "destroy 실행-조회수 백업"이 찍힐 것이고, 브라우저에는 접속수를 카운트하여 보여줄 것입니다. 이때 브라우저 새로고침을 이용해서 접속수를 카운트 하다가 서버를 중단시키게 되면 init(), service(), destroy() 각 메소드들의 실행 숫자를 세보실 수 있을 것입니다.

0개의 댓글