5장. 서블릿 이해하기
  • JSP 이전에 동적 웹 페이지를 처음으로 구현한 방법은 서블릿이다. JSP은 서블릿의 문제점을 보완, 하지만 많은 기능이 서블릿의 기능을 따른다.
  • 웹 애플리케이션을 개발할 때도 JSP와 서블릿이 각자의 고유한 역할을 나누어 기능을 구현함

 

5.1 서블릿이란?

서블릿 : 서버 쪽에서 실행되면서 클라이언트의 요청에 따라 동적으로 서비스를 제공하는 자바 클래스

 

서블릿의 동작 과정

1) 클라이언트가 웹 서버에 요청

2) 웹 서버는 그 요청을 톰캣과 같은 웹 애플리케이션 서버(WAS)에 위임

3) WAS는 각 요청에 해당하는 서블릿을 실행

4) 서블릿은 요청에 대한 기능을 수행 후 결과를 반환

5) 클라이언트에 전송

 

서블릿의 특징

  • 서버 쪽에서 실행, 웹 브라우저에서 요청 시 기능을 수행
  • 기존의 정적인 웹 프로그램의 문제점을 보완하여 동적인 여러가지 기능(DB연동, 계산 등)을 제공
  • 스레드 방식으로 실행
  • 자바로 만들어져 자바의 특징(객체지향)을 가짐
  • 독자적으로 실행되지 못하고 톰캣과 같은 JSP/Servlet 컨테이너*에서 실행되고 그 종류는 상관없이 실행 됨
  • 보안 기능을 적용하기 쉬움

* JSP/Servlet 컨테이너 => 여기선 자바 기반 오픈소스로 제공되는 톰캣을 사용

 

5.2 서블릿 API 계층 구조와 기능

사진 출처 : https://velog.io/@cocodori/Servlet

  • 서블릿 api는 Servlet과 ServletConfig 인터페이스를 구현해 제공
  • GenericServlet 추상 클래스 : 위 두 인터페이스의 추상 메서드를 구현
  • HttpServlet : GenericServlet을 상속받음

 

<서블릿 API 구성 요소 특징>

  • Servlet 인터페이스 : Servlet 관련 추상 메서드를 선언
  • ServletConfig 인터페이스 : Servlet 기능 관련 추상 메서드가 선언
  • GenericServlet 클래스 : 상위 두 인터페이스를 구현하여 일반적인 서블릿 기능을 구현한 클래스
  • HttpServlet 클래스 : GenericServlet을 상속받아 HTTP 프로토콜을 사용하는 웹 브라우저에서 서블릿 기능을 수행

                               : 웹 브라우저 기반 서비스를 제공하는 서블릿을 만들 때 상속받아 사용

                               : 요청 시 service()가 호출되면서 doGet()이나 doPost()가 차례대로 호출 됨

       => 우린 이 클래스를 상속받아 HTTP 프로토콜로 동작하는 웹 브라우저의 요청을 처리하는 서블릿을 만드는 것임!

 

<HttpServlet의 여러 가지 메서드 기능>

  • protected doGet(HttpServletRequest req, HttpServletResponse resp) : 서블릿이 GET 요청을 수행하기 위해 service()를 통해 호출
  • protected doPost(HttpServletRequest req, HttpServletResponse resp) : POST 요청
  • protected doDelete(HttpServletRequest req, HttpServletResponse resp) : DELETE 요청
  • protected doHead(HttpServletRequest req, HttpServletResponse resp) : HEAD 요청

 

  • public service(ServletRequest req, ServletResponse resp) : 요청을 protected service()에게 전달 함
  • protected service(ServletRequest req, ServletResponse resp) : 요청을 public service()에서 전달 받아 do~를 호출

 

5.3 서블릿의 생명주기 메서드

서블릿도 자바 클래스이므로 '초기화 -> 서비스 수행(db연동) -> 소멸' 과정을 거치고 거칠 때 마다 서블릿 클래스의 생명주기 메서드가 호출 됨

 

<서블릿의 생명주기 메서드>

  • 초기화, init() : 서블릿의 맨 처음 요청일 때 한 번만 호출됨. 서블릿 생성 시 초기화 작업을 주로 수행
  • 작업 수행, doGet()/doPost() : 서블릿 요청 시 매번 호출 됨, 클라이언트가 요청하는 작업을 수행 => 구현 필수
  • 종료, destory() : 메모리에서 소멸될 때 호출 됨, 서블릿의 마무리 작업을 주로 수행

 

5.4 FirstServlet을 이용한 실습

사용자 정의 서블릿을 실제로 만들어서 서블릿의 동작 과정 실습하기.

<이클립스에서 서블릿을 만들고 실행하는 과정>

  1. 사용자 정의 서블릿 클래스 만들기 ( * 클래스 패스 설정 servlet-api.jar 라이브러리로)
  2. 서블릿 생명주기 메서드 구현
  3. 서블릿 매핑 작업
  4. 웹 브라우저에서 서블릿 매핑 이름으로 요청하기

사용자 정의 서블릿 => HttpServlet 클래스를 상속받음, 생명주기 메서드(init, doGet, destroy)를 오버라이딩 구현

* 서블릿 API들은 톰캣의 servlet-api.jar 라이브러리로 제공되므로 클래스 패스 설정 필요

 

1. New > Dynamic Web Project(Generate web.xml~ 체크)

   > 프로젝트 우클릭 후 Build Path > Configure Build Path...

   > Libraries 탭 > Add External JARs... > tomcat9\lib\servlet-api.jar 선택 후 열기 > Apply and Close

   > Java Resources > src 우클릭 > New> Package

   > 패키지 우클릭 > New > Class

 

2. HttpServlet 상속 후 init(), doGet(), destory 구현

 

3. 브라우저에서 서블릿 이름으로 요청 >> http://~/프로젝트이름/패키지이름이 포함된 클래스 이름

   (ex. http://~/pro05/sec01.ex01.FirstServlet)   => 이 방법은 좋지 않음,

 

3. 서블릿 클래스 이름에 대응되는 서블릿 매핑 이름으로 실제 서블릿을 요청

1) 프로젝트>WebContent>WEB-INF>web.xml <web-app> 하위에

2) <servlet> 태그 안엔 실제 실행 하는 서블릿 클래스 설정(<servlet-class>),

3) <servlet-mapping>태그 안에는 논리적인(브라우저에서 요청되는) 이름을 적어 주고(<url-pattern>)

4) 두 태그 내의 동일한 <servlet-name> 태그 값으로 논리적인 서블릿 이름과 실제 서블릿 클래스를 연결함

ex.

  <servlet>
    <servlet-name>aaa</servlet-name>
    <servlet-class>sec01.ex01.FirstServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>aaa</servlet-name>
    <url-pattern>/first</url-pattern>
  </servlet-mapping>

=> 매핑 이름으로 요청 시 값이 같은 <servlet> 태그 안의 <servlet-name>태그와 연결 됨

 

** 다수의 서블릿 매핑하기

일반적인 웹 애플리케이션은 각 기능에 대한 서블릿을 따로 만들어서 서비스를 제공, 즉 프로젝트에서 여러 개의 서블릿을 만들어 사용. 복수개의 <servlet> 태그, 복수개의 <servlet-mapping>태그가 필요하고 같은 태그끼리 위치시킨다

 

4. 프로젝트를 톰캣 서버에 등록+실행 후 브라우저에서 매핑 이름으로 요청(http://~/프로젝트이름(컨텍스트이름)/매핑이름)

 

5.5 서블릿 동작 과정

1. 클라이언트1이 요청하면 톰캣은 해당 서블릿이 메모리에 로드 되어있는지 확인

2. 1의 결과 최초의 요청이므로 init() 메서드를 호출하여 해당 서블릿 인스턴스를 메모리에 로드한다.

3. doGet() / doPost() 메서드를 호출해서 서비스한다.

 

4. 클라이언트2가 동일한 서블릿을 요청한다.

5. 해당 서블릿이 메모리에 로드되어 있는지 확인 > 메모리에 있으므로 바로 doGet() / doPost() 메서드 호출해서 서비스

 

=> 스레드 방식!! 서블릿은 동일한 작업의 경우 메모리에 존재하는 서블릿을 재사용하여 빠르고 효율적

 

5.6 애너테이션을 이용한 서블릿 매핑

  • 5.4에서 했던 것 처럼 web.xml에 서블릿을 직접 매핑하는 것은 복잡. >> 각 서블릿 클래스 위에 '@'를 이용해서 서블릿 표시 => @WebServlet("/서블릿매핑이름")

 (애너테이션 : 소스 코드에 직접 기능을 설정하는 방법)

  • 방법 : @WebServlet을 이용 + HttpServlet을 상속 받기

 

<이클립스에서 서블릿 생성 시 매핑 애너테이션 추가하기>

패키지우클릭> New > Servlet > Class name 입력 후 Next

> 기본으로 뜨는 URL mapping을 선택 후 Edit > 서블릿 매핑 이름 등록

> Next 후 나오는 화면에서 Constructors from superclass 옵션 체크박스의 체크를 해제 + 오버라이딩할 생명주기 메서드를 추가(init, destroy, doGet, doPost)

 

* 애너테이션을 사용할 때는 매핑 이름이 이미 사용된 다른 매핑 이름과 중복되지 않도록 주의

* serialVersionUID : 서블릿 클래스의 직렬화를 위해 이클립스에서 자동으로 생성되는 상수, 여기선 사용하지 않으므로 삭제하고 경고떠도 무시