본문 바로가기

Web/Servlet

Servlet 이해하기

Servlet 이란

웹서버에서 안에서 클라이언트의 요청에 응답하는 자바 프로그램을 말한다. 우리는 서블릿을 만들기 위해 HttpServelt 클래스를 상속 받아서 만들게 되는데, 이는 Servelt Interface를 상속받아 만들어진 추상클래스이다. Servlet을 이해하기 위해서는 Servlet Interface가 어떻게 구성되어있는지 살펴보고, HttpServelt 추상 클래스에는 어떤 함수들이 구현되어있는지 살펴보면서 Servlet의 동작 과정을 이해해보려고 한다.

서블릿의 상속 관계

1.  Servlet Inteface 주요함수 살펴보기

위 그림에서 볼 수 있듯이 Servlet에는 init, service, destory 세개의 함수가 정의 되어있다. 

1)init

public void init(ServletConfig config) throws ServletException;

서블릿 컨테이너는 초기화하기 위해 한번한 init을 호출한다. 서블릿이 요청을 수신하기 위해서는 init이 성공적으로 완료되어야한다. 

만약 init이 ServletException을 throw하거나 웹서버에 정의된 시간 안에 리턴하지 않는다면, 서블릿 컨테이너가는 해당 서블릿은 서비스 상태로 만들 수 없다.

2)service

public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;​

서블릿이 요청에 응답하기 위해 서블릿 컨테이너에 의해서 호출된다. 이 메소드는 init이 성공적으로 수행된 후에만 호출된다. 상태 코드(status code)는 오류를 발생시키거나 보내는 서블릿을 위해서 설정되어야한다. 

서블릿은 대게 동시에 다수의 요청을 처리할 수 있는 멀티스레스 서블릿 컨테이너 안에서 실행된다. 개발자들은 파일이나 네트워크, 서블릿클래스와 인스턴스 변수들과 같이 공유되는 자원에 동시에 접근하는 것을 알고 있어야한다. 

@req : 클라이언트의 요청을 담고 있는 ServletRequest 객체

@res : 서블릿의 응답을 답고 있는 ServletResponse 객체

3)destory

public void destroy();

서블릿이 서비스에서 제외됨을 알리기 위해 서블릿 컨테이너에서 호출된다. 이 메소드는 서블릿 안에있는 모든 스레트가 종료되거나 타임 아웃 기간이 초과되었을 때 한번만 불린다. 서블릿 컨테이너가 이 함수를 부르면, 서블릿 컨테이너에서 service 메소드를 다시는 이 서블릿에서 부를 수 없다.

이 메소드는 서블릿에게 메모리나 파일이나 스레드와 같은 자원을 정리할 기회를 준다.

2. HttpServlet 추상 클래스

1) service

    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
		//메소들을 가져와 각 메소드에 맞는 함수를 호출한다.
        String method = req.getMethod();
		//간략하게 표시함
        if (method.equals(METHOD_GET)) {
            doGet(req, resp);
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
        /* 생략 doHead, doPut, doDelete 와 같은 처리 부분들 */
        } else {
            // 에러!!
        }
    }

Http request를 인풋으로 받아 해당 요청의 method에 따라서 doGet, doPost, doPut 등과 같은 함수들을 호출한다. 우리는 주로 HttpServlet 추상 클래스를 상속받아 doGet(), doPost() 메소드를 오버라이드 하며, 클라이언트의 요청을 처리하게 된다. 

3. Servlet은 어떻게 찾는 걸까?

Tomcat이 Servlet 컨테이너로서 우리들이 만든 Servlet들을 적절히 찾아 service 함수를 호출해준다. 이 과정은 과연 어떻게 일어나는 것일까?

톰캣을 시작하게 되면, MapperListener 라는 클래스에서 우리가 가지고 있는 서블릿들의 정보를 Mapper 클래스에 저장하여 가지고 있게 된다. 

클라이언트로부터 요청이 들어오면 해당 요청을 파싱하고, 어떤 서블릿에 들어가야 될지 찾게 된다. 이 과정은 postParseRequest 함수안에서 이루어지게 되며, 여기에서 path가 일치하는 servlet를 찾게 된다. 처음에는 context path의 일치여부를 보고, 이후에 다시 매칭되는 url을 찾게 된다.

    private final void internalMap(CharChunk host, CharChunk uri,
            String version, MappingData mappingData) throws IOException {
        /* 
        생략 
        uri와 일치하는 contexts를 찾는 과정. contexts는 bootstrap 할때 이미 형성되어 있는 값이다.
        */
        ContextList contextList = mappedHost.contextList;
        MappedContext[] contexts = contextList.contexts;
        int pos = find(contexts, uri);
        if (pos == -1) {
            return;
        }
        /* 
        생략
        계속 진행되며, mappingData에 찾는 context 정보를 mapping 시켜주게 된다 
        */
    }

 

find 함수는 이분 탐색으로 실행이 되며, 탐색 시간은 O(log(n))이기 때문에 우리가 서블릿을 많이 만들더라도 서블릿을 찾는데 걸리는 시간을 크게 증가하지 않을 것이다. 

 

 

 

 

반응형