Servlet

서블릿 특징

  • 서버 쪽에서 실행되면서 클라이언트의 요청에 따라 동적으로 서비스를 제공하는 자바 클래스
  • 서블릿은 일반적으로 HTTP를 통해 웹 클라이언트로부터 요청을 수신하고 응답한다.
  • 컨테이너에서 스레드 방식으로 실행되며 컨테이너 종류에 상관없이 실행된다.(플랫폼 독립적)

Servlet 인터페이스

서블릿을 초기화하고, 요청을 처리하고, 서블릿을 서버에서 삭제하는 방법에 대해 정의한다. 즉, 서블릿 생명주기에 관련된 추상 메서드를 제공한다.

ServletConfig 인터페이스

Servlet 초기화에 필요한 정보를 전달하기 위한 Config 객체다.

GenericServlet 클래스

GenericServlet 추상클래스는 Servlet과 ServletConfig 인터페이스를 구현하여 일반적인 서블릿 기능을 구현한 클래스다.
GenericServlet을 상속받아 구현한 사용자 서블릿은 사용되는 프로토콜에 따라 각각 service()를 오버라이딩해서 구현한다.

HttpServlet 클래스

HttpServlet은 GenericServlet 추상클래스를 상속받아 HTTP 프로토콜을 사용하는 웹 브라우저에서 서블릿 기능을 수행한다. 웹 브라우저 기반 서비스를 제공하는 서블릿을 만들 때 상속받아 사용한다. service()가 호출되면서 요청 방식에 따라 doXXX()가 호출된다.

서블릿의 인스턴스화

ServletContext

서블릿 컨테이너(아파치 톰캣)가 시작되면, 해당 서블릿 컨테이너는 모든 웹 애플리케이션들을 배포하고 로드 한다.
웹 애플리케이션이 로드 되면 서블릿 컨테이너는 한 개의 ServletContext를 생성하여, 서버의 메모리에 보관한다. 이후 web.xml을 파싱하여 <servlet> <filter> <listener>(혹은 @WebServlet @WebFilter @WebListener) 가 발견되면 해당 클래스들을 한번 인스턴스화 하고 서버의 메모리에 보관한다.

각각의 인스턴스화 된 필터는 본인의 init 메서드가 즉시 실행(invoke)된다.

서블릿 컨테이너가 종료되면 모든 웹 애플리케이션들을 언로드하고, 모든 초기화된 서블릿 및 필터의 destroy 메서드를 실행 후 ServletContext, Servlet, Filter 및 Listener 인스턴스들을 전부 삭제한다.

서블릿에 0보다 큰 <servlet><load-on-startup> 또는 @WebServlet(loadOnStartup) 값이 있을 경우 init 메서드도 시작 중에 즉시 실행 된다. 이러한 서블릿은 해당 값에 지정된 순서대로 초기화된다. 1개 이상의 서블릿이 동일한 값을 가지고 있을 경우에는 web.xml 또는 @WebServlet 클래스로딩에 등장하는 순서대로 로드된다. 만약 load-on-startup 값이 없을 경우 해당 서블릿에 처음으로 HTTP request가 올 때 init 메서드가 실행된다. 이러한 이유로 첫 요청을 보낸 사용자는 응답속도가 늦다는 단점이 발생한다.

HttpServletRequest, HttpServletResponse

서블릿 컨테이너는 특정 포트 번호에서 HTTP request를 받는 웹 서버에 연결된다. 클라이언트가 HTTP request를 보낼 때, 서블릿 컨테이너는 새로운 HttpServletRequest와 HttpServletResponse 인스턴스를 생성하고 해당 인스턴스를 미리 정의된 필터 체인과 서블릿 인스턴스를 통과하도록 한다.

필터의 경우 doFilter 메서드가 호출된다. chain.doFilter(request, response)를 호출하면 request와 response가 다음 필터로 넘어가거나, 남아있는 필터가 없는 경우 서블릿에 도달한다.

서블릿의 경우 service 메서드가 호출된다. 기본적으로 이 메서드는 request.getMethod() 기반으로 doXXX() 메서드 중 하나를 호출한다. 해당되는 메서드가 서블릿에 없으면 HTTP 405 에러가 발생하게 된다.

request 객체는 header와 body 같은 HTTP request에 대한 모든 정보를 갖고 있다. response 객체는 원하는 방식으로 HTTP 응답을 보낼 수 있다.

HTTP 응답이 완료되면 request 객체와 response 객체는 모두 재활용된다.

HttpSession

클라이언트가 처음으로 웹 애플리케이션을 방문하거나 request.getSession()을 통해 HttpSession을 처음으로 가져오면 서블릿 컨테이너는 새로운 HttpSession 객체를 생성하고 길고 유니크한 ID를 생성 후, 서버의 메모리에 저장한다. 또한 서블릿 컨테이너는 JSESSIONID라는 이름을 key로, 생성한 session ID를 value로 하여 HTTP 응답의 Set-Cookie 헤더에 cookie로 설정한다.

웹 브라우저와 웹 서버가 준수해야 할 HTTP Cookie 스펙에 따라 클라이언트는 cookie가 유효한 동안은 cookie header의 후속 request에 cookie를 반환해야 한다. 즉, 유니크 ID는 만료되지 않도록 만료기간이 session이어야 하며 도메인 경로는 일치해야 한다.

서블릿 컨테이너는 들어오는 모든 HTTP request의 cookie header에서 JSESSIONID라는 이름의 cookie가 있는지 확인하고 해당 값을 사용하여 서버의 메모리에 저장된 HttpSession을 가져온다.

HttpSession은 설정된 session-timeout 값(기본값은 30분) 까지만 살아있다. 클라이언트가 timeout 보다 오래 웹 애플리케이션을 방문하지 않으면 서블릿 컨테이너가 session을 삭제한다. 그러면 모든 request는 지정된 cookie가 있더라도 더 이상 동일한 session에 엑세스 할 수 없으며, 서블릿 컨테이너는 새로운 session을 생성한다.

클라이언트 측에서는 웹브라우저 인스턴스가 실행되는 동안 session cookie가 활성화된다. 따라서 클라이언트가 웹브라우저 인스턴스(모든 탭/창)을 닫으면 클라이언트 session이 삭제된다. 이로 인해 새로운 HTTP Session이 생성되고 새로운 session cookie가 사용된다.

서블릿의 스레드 안정성

ServletContext는 웹 애플리케이션이 살아있는 한 계속 살아있다. 그리고 모든 session에서 모든 request간에 공유된다. 서블릿과 필터는 모든 request에서 공유된다. 그래서 request마다 매번 init(), destroy()를 다시 실행하는 비용을 없앤다.

request나 session에서 사용하는 데이터를 서블릿이나 필터의 인스턴스 변수로 할당해서는 안 된다. 다른 session의 모든 request간에 공유되어 스레드로부터 안전하지 않기 때문이다.

public class MyServlet extends HttpServlet {
    // 스레드 안전하지 않은 변수
    private Object nonThreadSafeObject;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      // 스레드 안전한 변수
      Object threadSafeObject;
    }
}

서블릿 scope

스코프 종류 해당 서블릿 API 속성의 스코프
application scope ServletContext 애플리케이션 전체에 대해 접근 가능
session scope   HttpSession   같은 브라우저에서만 접근 가능
request scope   HttpServletRequest   해당 요청/응답 사이클에서만 접근 가능

서블릿 관련 Listener

서블릿 관련 리스너 기능
ServletContextAttributeListener 컨텍스트 객체에 속성 추가/제거/수정 이벤트 발생시 처리
HttpSessionListener 세션 객체에 생성/소멸 이벤트 발생시 처리
ServletRequestListener 클라이언트의 요청 이벤트 발생시 처리
ServletRequestAttributeListener 요청 객체에 속성 추가/제거/수정 이벤트 발생시 처리
HttpSessionBindingListener 세션에 바인딩/언바인딩된 객체를 알려주는 이벤트 발생시 처리
ServletContextListener 컨텍스트 객체의 생성/소멸 이벤트 발생시 처리
HttpSessionActivationListener 세션의 활성화/비활성화 이벤트 발생시 처리

Categories:

Updated:

Comments