Backend/JAVA

Servlet 이란 무엇일까 [개념편]

뜨거운 개발자 2024. 5. 7. 23:19

서블릿이란

서블릿은 CGI와 같이 자바를 사용하여 웹 서버에서 동적으로 컨텐츠를 생성하고, 클라이언트에게 응답을 전송하는 기술입니다.

서블릿을 이해하기 위해서 동적컨텐츠와 CGI가 무엇인지 먼저 이해가 필요합니다.

정적/동적 컨텐츠

정적인 콘텐츠는 미리 준비된 문서 즉 변화하지 않는 리소스를 제공하는 것을 의미합니다.

즉 항상 똑같은 사진이나 책처럼 변화하지 않는 문서 등 변화하지 않는 미리 준비된 콘텐츠 입니다.

웹 초기에는 정적인 컨텐츠만 제공했지만 데이터의 변화에 따라 프로그램이 생성한 컨텐츠를 동적으로 보여주고 싶은 니즈가 발생했습니다.

즉 동적인 컨텐츠는 미리 준비된 콘텐츠가 아니라 프로그램을 실행해서 제작해서 주는 콘텐츠입니다.

(이미지 출처: 프로가 되기 위한 웹기술 입문)

 

서블릿은 왜 생겨났는가?

먼저 서블릿의 역사를 알기 위해 서블릿이 왜 생겨나야 했나 이해해야합니다. 그것을 위해서는 먼저 CGI(Common Gateway Interface) 개념부터 알아야합니다.

Cgi와 서블릿의 등장

출처 : 프로가 되기 위한 웹기술 입문

CGI란 서버에서 다른 프로그램을 동적으로 실행시켜 요청,결과를 주고받는 표준 혹은 형식입니다.

CGI는 호환성이 좋고, 간편하지만 사용자가 한번 요청할 때마다 웹서버가 프로세스를 하나씩 만들게 하기 때문에 사용자가 많아질수록 서버의 부하가 커진다는 단점이 있었습니다.

즉 프로세스를 생성하는 방식은 실행하고 종료하는 것이 매우 느리며, 여러 사용자의 접속의 경우 서버의 자원을 너무 많이 잡아먹는다는 단점이 있었습니다.

그렇기 때문에 새로운 규약들이 등장하게 되었는데, 그 중 하나가 Java 진영의 서블릿 입니다.

서블릿은 두가지 방법으로 CGI의 문제점을 개선하였습니다.

  1. 프로세스 단위가 아닌 쓰레드 단위로 동작
  2. 동일한 작업의 경우 서블릿은 초기화를 매번 진행하지 않고 메모리에 존재하는 서블릿을 재사용

서블릿(servlet)의 기본개념

서블릿은 요청-응답 프로그래밍 모델을 기반으로 클라이언트 요청과 통신하고 동적 응답을 생성하는 방법을 제공합니다. 서블릿은 모든 유형의 요청에 응답할 수 있지만 대부분의 경우 웹 서버에서 호스팅하는 웹 애플리케이션에서 사용됩니다. 이러한 애플리케이션의 경우 Java 서블릿은 특정 서블릿 클래스인 HTTP를 정의합니다.

일반적으로 웹서버는 정적인 페이지만 제공할 수 있습니다. 이전에 웹서버 과제에서 CGI를 다뤘었는데(추후 게시물로 추가 예정), 서블릿은 자바로 구현한 CGI라고 이야기 합니다.

서블릿은 CGI와 같이 자바를 사용하여 웹 서버에서 동적으로 컨텐츠를 생성하고, 클라이언트에게 응답을 전송하는 기술로 간단한 메서드 호출만으로 사용이 가능하도록 만들어졌습니다.

출처 : 프로가 되기 위한 웹기술 입문

 

서블릿 작성

서블릿을 작성하기 위해 Java 서블릿 API는 javax.servlet 및 javax.servlet.http 패키지로 인터페이스와 클래스를 제공합니다. 서블릿 인터페이스는 서블릿의 수명 주기를 정의합니다.

웹 애플리케이션에서 클라이언트 요청을 처리하려면 GenericServlet 클래스 또는 HTTPServlet(HTTP 요청/응답인 경우) 클래스를 확장해야 만 합니다.

서블릿의 작동순서

아래는 서블릿이 HTTP요청이 들어왔을 때 어떻게 작동하는지 보여줍니다.

  1. 클라이언트로부터 HTTP요청 들어옵니다.
  2. 웹서버는 해당 요청을 톰캣과 같은 WAS에게 위임합니다.
  3. 이떄 HttpServletRequest와 HttpServletResponse 객체가 생성됩니다.
  4. WAS는 해당 요청을 서블릿 컨테이너 라는 녀석에게 전달합니다.
  5. 서블릿 컨테이너는 요청을 처리할 서블릿을 찾아 실행합니다. (web.xml 참고)
  6. 서블릿의 실행 결과는 HTTP 응답 형태로 클라이언트에게 전송됩니다.

 

서블릿 컨테이너

클라이언트로부터 요청이 오면 컨테이너는 HttpServletRequest, HttpServletResponse 두 객체를 생성합니다. 그리고 post,get 여부에 따라서 동적인 페이지(또는 json 등) 을 생성해서 응답을 보냅니다.

서블릿 컨테이너라는 개념이 등장하는데, 쉽게 말하면 서블릿은 어떤 역할을 할지 적어둔 명세서라고 보면, 서블릿 컨테이너는 해당 명세를 보고 실행하는 환경이라고 생각하면 됩니다.

서블릿 컨테이너의 역할

  1. 웹서버와 통신지원 :서블릿 컨테이너는 서블릿과 웹서버가 손 쉽게 통신할 수 있도록 도와줍니다.
    • url을 특정 서블릿에 매핑해, URL을 요청한 유저에 올바른 엑세스 권한이 있는지 확인합니다.
    • 이전에 웹 서버를 제작하는 게시물에서 다뤘듯 통신을 하려면 socket을 만들고 listen, accept하는 과정을 겪어야만 합니다. 하지만 서블릿 컨테이너는 이런 기능을 래핑해서 API로 제공해줍니다. 서블릿 컨테이너 덕분에 개발자는 비즈니스 로직에 더 집중 할 수 있습니다.
    • JSP실행 페이지 관리 등, 서블릿의 응답은 HTML, JSON 등 다양한 형태로 데이터를 생성해 응답 가능합니다.
  2. 서블릿 생명주기 관리 :
    • 즉 서블릿 클래스를 로딩해서 인스턴스화하고, init() 메소드를 호출하고 요청에 따라서 적절한 서블릿 메소드를 호출합니다.
    • 추가적으로 수명이 다된 서블릿을 적절하게 가비지 콜렉터를 호출해서 자원관리도 도와줍니다.
    • 서블릿 컨테이너는 서블릿의 생명주기를 관리하며 요청에 따라 서블릿을 로딩, 초기화, 실행, 종료합니다.
  3. 멀티 쓰레드 지원 및 관리 :
    • 서블릿 컨테이너는 새로운 Request가 올때마다 자바 쓰레드를 하나 생성하는데 HTTP 서비스 메소드를 실행하고 나면 쓰레드는 자동으로 죽게 됩니다.
    • 원래는 개발자가 쓰레드를 관리해야 하지만 서버가 알아서 다중 쓰레드를 생성 및 운영해주기 때문에 걱정할 필요는 없다.
    • (자바에서의 쓰레드는 JVM(Java Virtual Machine) 위에서 실행되는 단위이며, 운영체제의 쓰레드와 비슷하게 동작하지만, 완전히 동일하진 않습니다. 이 차이점은 자바 쓰레드가 JVM을 통해 관리되기 때문에 발생합니다. JVM은 다양한 운영체제에서 자바 애플리케이션을 실행할 수 있도록 하는 가상 머신이며, 자바 쓰레드를 운영체제의 쓰레드로 매핑합니다.)
  4. 선언적 보안관리 :
    • 서블릿 컨테이너를 사용하면 개발자는 보안 관련 내용을 서블릿이나 자바 클래스에 구현하지 않아도 됩니다. 대신 일반적으로 보안 관리를 XML배포 기술자에 기록하기 때문에 보안애 대하여 수정할 일이 생겨도 자바 코드를 수정해서 다시 컴파일 하지 않아도 됩니다.

 

서블릿과 스프링

서블릿 만으로도 웹 어플리케이션 개발 가능합니다. 하지만 서블릿은 스프링과 결합하면 더 좋습니다.

스프링은 서블릿 기반의 웹 어플리케이션 개발을 위한 스프링 MVC를 제공하기 때문입니다.

Spring MVC는 Model, View, Controller 의 구조를 가집니다.

이를 통해 각 부분을 명확하게 분리하여 개발이 가능해서 효율적인 개발이 가능합니다. 이러한 특징 때문에 서블릿은 보안 기능을 적용하기 쉽습니다.

MVC패턴에서 서블릿은 컨트롤러로 이용됩니다.

서블릿 구현 형식

HttpServlet 구현코드를 보면 많은 함수가 있지만 init,doGet,distroy 함수를 봅시다.

아래 클래스는 실제로 서블릿을 구현하는 예시입니다.

HttpServlet을 상속 받아서 필요한 함수를 Override 해서 구현하면 서블릿을 구현해볼 수 있습니다.

public class MyServlet extends HttpServlet {
	@Override
    public void init() {
    ...
	}
    
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
    ...
    }
    
    @Override
    public void destroy() {
    ...
    }
}

여기에서 init(), doGet(), destroy() 세가지 함수를 오버라이딩 한다는 것을 보고 넘어갑시다.

서블릿의 생명주기

  1. 클라이언트 요청이 들어오면 서블릿 컨테이너는 해당 서블릿이 메모리에 있는지 확인합니다.
  2. 없다면 init()메서드를 호출해서 메모리에 적재합니다.
    • init()은 처음 한번만 실행되기 때문에 서블릿이 생성될 때 초기화 작업을 하고, 서블릿 스레드에서 공통적으로 사용해야 하는 것이 있다면 오버라이딩을 통해서 구현합니다.
    • 만약 서블릿이 변경된 경우에는 기존 서블릿은 destory()하고 init()을 통해 새로운 내용을 메모리에 다시 적재합니다.
  3. int()이 호출 된 후 클라이언트의 요청에 따라서 service()메소드를 통해 요청에 대한 응답이 doGet()과 doPost()로 분기됩니다.
    • 이때 서블릿 컨테이너가 클라이언트 요청이 오면 가장 먼처 생성했던 HttpServletRequest, HttpServletResponse에 의해 request와 response객체가 생성됩니다.
  4. 컨테이너가 서블릿에 종료 요청을 한다면 destroy() 메소드가 호출되는데, 이것 역시 한번만 실행되며, 종료시에 처리되야 하는 작업들은 모두 destory() 메소드를 오버라이딩 해서 구현하면 됩니다.

마치며

이번 게시물에서는 서블릿의 개념적 부분에 집중한 게시물입니다.

다음 게시물에서는 실제 서블릿이 어떻게 동작하는지 더 자세하게 설명하도록 하겠습니다.

728x90

'Backend > JAVA' 카테고리의 다른 글

서블릿이란 무엇인가 [서블릿 실행 흐름 편]  (0) 2024.05.08