[Spring] Servlet이란? - JSP, DispatcherServlet

koline·2024년 10월 9일

Spring

목록 보기
15/15

Servlet


Servlet이란 자바 기반의 서버 측 컴포넌트로, 클라이언트의 HTTP 요청을 처리하고 HTTP 응답을 생성하는 역할을 한다.

즉, 동적 웹사이트를 만들기 위해 꼭 필요한 역할을 제공한다는 것이다.

Servlet 없이 웹사이트를 만들어야 한다고 생각해보자.

http://domain.com/main/main.html 요청을 통해 메인페이지의 html을 반환해주고 거기서 어떤 버튼을 누르면 http://domain.com/menu/menu1.html로 이동하는 방식의 정적인 웹사이트가 될것이다.

이것은 매우 빠른 웹사이트일 것임은 매우 분명하지만, 요청에 따른 동적인 처리는 불가능할 것이다.

이 점을 보완하기 위해 등장한 것이 JavaServlet 객체이다.




Servlet의 생김새


public class TestServlet extends HttpServlet {

    public void init(ServletConfig config) throws ServletException {
        super.init();
    }

    public void destroy() {
        super.destroy();
    }

    protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        super.service(req, res);
    }
}

Servlet은 기본적으로 위와 같이 생겼다. Servlet 인스턴스가 생성, 소멸할 때의 동작과 이 서블릿이 하는 역할이 정의되어 있다.

그렇다면 이 Servlet이 어떻게 HTTP 요청을 동적으로 처리할 수 있게 할까?

애플리케이션이 실행되면 WAS에는 Servlet의 생명주기를 관리하는 컨테이너인 ServletContainer가 위치하게 된다.

<servlet>
  <servlet-name>TestServlet</servlet-name>
  <servlet-class>servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>TestServlet</servlet-name>
  <url-pattern>/test</url-pattern>
</servlet-mapping>

ServletContainer는 요청이 들어오면 위와 같은 Servlet 설정파일을 기반으로 이 요청이 어떤 요청이고 어떤 Servlet이 담당하는지 파악한다.

그 후에 해당 Servlet의 인스턴스가 컨테이너 내에 존재한다면 이 인스턴스를 그대로 사용하고, 존재하지 않는다면 인스턴스를 생성하고 Servlet 객체의 init() 메서드를 실행한다.

그 후에 ServletContainer 내부에 Thread를 생성하고 HttpServletRequest 객체와 HttpServletResponse 객체를 인자로 service(req, res) 메서드를 호출한다.

그리고 마지막으로 응답을 반환한 후 HttpServletRequest 객체와 HttpServletResponse 객체를 소멸시키고 마무리한다.

이 때, 생성된 Servlet은 소멸되지 않는데 그 이유는 Servlet싱글톤으로 관리되기 때문이다.

ServletContainer는 효율적인 Servlet 사용을 위해 이를 보관하고 있다가 다음에 같은 요청이 오면 이 Servlet 인스턴스를 사용해 요청을 처리한다.

이러한 Servlet 생명주기 관리가 개발자가 아닌 컨테이너에게 위임되게 된다.




JSP


JSPHTML 내에 자바 코드를 삽입하여 동적 웹 페이지를 생성할 수 있는 기술이다. JSP 파일은 서버에서 실행되며, 클라이언트의 요청에 따라 HTML 콘텐츠를 동적으로 생성하여 응답으로 보낸다.

JSP가 서블릿과 연관되는 이유는 JSP가 서블릿으로 변환되어 실행되기 때문이다.

즉, http://domain.com/main.jsp의 요청이 오면 ServletContainer는 이 경로에 있는 main.jsp 파일을 찾아서 서블릿으로 변환한다.

이 때 JSP에 있는 Java 코드를 실행하여 처리하고 동적인 컨텐츠가 생성되게 된다.

최종적으로 ServletContainerhtml 응답을 생성하여 반환한다.

이후에 이 방식은 JSPControllerView의 역할을 담당하는 MVC1 패턴ServletJSP의 역할을 분리하여 ServletController의 역할을 담당하고 JSPView의 역할만을 담당하는 MVC2 패턴으로 발전한다.




DispatcherServlet


이후에 StrutsSpring과 같은 프레임워크들이 등장했는데, 이러한 프레임워크의 관점에서 위와 같이 ServletContainer가 필요한 스레드를 계속 생성하는 방식은 매우 비효율적이다.

앞선 방식에서 스레드의 생성은 서블릿 컨테이너가 담당하는데, 요청이 여러개 동시에 온다면 여러개의 스레드를 생성해서 (멀티스레드) 처리한다.

요청이 매우 많이 온다면 부하가 매우 늘어나고 서버가 뻗을 수도 있다.

이 상황을 음식점으로 묘사해보자. 음식점에는 라면, 만두, 김밥 3가지 메뉴가 있다.

위와 같은 방식에서 라면 요청이 들어오면 라면 서블릿이 라면 주문을 받고 라면을 만들어서 포장하고 서브한다. 김밥, 만두 요청이 들어오면 김밥, 만두 서블릿이 각각 똑같은 과정을 거친다.

여기서 공통되는 주문을 받고 서빙하는 과정은 서버가 따로 담당하고, 서블릿은 각자 자신의 담당 음식을 만들기만 하면 더 효율적인 프로세스가 될 것이다.

이 서버의 역할을 하도록 프레임워크들에서 만든 것을 프론트 컨트롤러라고 한다.

그리고 Spring MVC에서 Struts와 같은 기존 프레임워크의 장점을 이어받아, 더 유연하고 확장 가능하게 만든 것이 DispatcherServlet이다.

DispatcherServlet프론트 컨트롤러 역할 뿐만 아니라 SpringApplicationContext와 통합되어, Bean의 생성과 관리, 의존성 주입(DI)을 활용한다.

이를 통해 Controller, Service, Repository 등 애플리케이션의 다양한 컴포넌트 간의 결합도를 낮추고, 코드의 재사용성과 테스트 용이성을 높여준다.

profile
개발공부를해보자

0개의 댓글