[CS] Java Servlet

허석진·2024년 8월 25일

CS

목록 보기
3/3

들어가기 전에

Servlet이라는 친구는 동적 웹 컨텐츠를 처리하기 위해 만들어졌다고하며, 항상 Applet, CGI 등이 항상 함께 등장한다.
그럼 대체 CGI는 뭐고 Applet은 뭐란 말인가? 그리고 그런 것들이 있었다면, Servlet은 왜 등장했고, 이것들이 등장하기 이전에 웹 사이트는 대체...? 라는 생각에 이 글을 작성하게되었다. (물론 면접 대비를 위한 것도 있다 ㅎ)

배경 지식

아래는 Java 공식 문서에서 설명하는 Java Servlet에 대한 설명이다.

웹이 서비스를 제공하는 데 사용되기 시작하자, 서비스 제공자들은 동적인 콘텐츠의 필요성을 인식하게 되었습니다. 초기 시도 중 하나였던 애플릿(Applet)은 클라이언트 플랫폼을 활용하여 동적인 사용자 경험을 제공하는 데 중점을 두었습니다.
동시에 개발자들은 서버 플랫폼을 사용하여 이 목적을 달성하려는 연구도 진행했습니다. 초기에는 CGI(Common Gateway Interface) 스크립트가 동적인 콘텐츠를 생성하기 위한 주요 기술로 사용되었습니다.
그러나 CGI 스크립트 기술은 널리 사용되었음에도 불구하고 플랫폼 종속성과 확장성 부족과 같은 여러 단점이 있었습니다. 이러한 한계를 해결하기 위해 Java Servlet 기술이 개발되었으며, 이는 동적이고 사용자 중심의 콘텐츠를 제공하는 휴대 가능한 방법으로 자리 잡게 되었습니다.

즉, 이전에 Applet이나 CGI등의 기술이 있었는데, 명확한 단점이 존재했고, 이를 보완한 기술로서 등장한 것이 Java Servlet이라는 것이다.
그렇다면 이 배경 지식 문항에서는, AppletCGI에 대해 설명하고, 이것들이 어떤 단점을 가지고 있었는지 알아보고자 한다.

Java Applet

Java Applet은 고정된 웹 페이지(HTML과 이미지, CSS 등)만을 클라이언트에게 전송할 수 있었던 시대의 기술이다.
지금이야 당연하다는 듯이 JS를 사용하고 있지만, 그 당시에는 JS와 Java Applet을 선택해서 사용했었고, 동적인 동작을 Client-side에 넘겨보자는 시도였다.

그럼, Java Applet은 어떻게 사용했던 걸까?

  1. 우선, 클라이언트에서 실행할 동작을 Java Class 파일로 정의한다. (Java 파일을 작성하고, 컴파일 하면 나오는 그거다.)
  2. HTML 파일에 Applet 태그를 추가하고 해당 태그에서 동작할 Java Class 파일을 속성으로 추가한다.
  3. 서버에서 HTML 파일과 Java Class 파일을 같이 보낸다.
  4. 클라이언트에 존재하는 JRE을 활용해서 Java Class 파일을 실행하여 화면이 동적으로 동작할 수 있게 한다.

위 내용을 읽다보면, 벌써 하기 싫은 내용이 보인다.
클라이언트 측에서 코드를 실행하는 방식이다 보니, Applet을 사용하는 웹사이트를 보려면, JRE이 깔려있어야한다는 것이다.
물론, Java를 사용하는 프로그램이 많으니 그럴 수 있지만, 모두가 그러진 않으니 사용자의 절반 이상은 불편해할 내용이다.
또한, 여느 프로그램이 그렇 듯 보안 취약점 역시 존재했고 Applet 만의 취약점을 관리하는 것 역시 쉬운일이 아니였다.
왜 웹 앱을 개발할 때 Java Applets 대신 JS를 쓰나요?

결국 이후에 다양한 발전된 기술들이 나오면서 대다수의 브라우저에서 Applet에 대한 지원을 중단했으며, Java 17버전에 와서는 Oracle도 지원을 중단해 역사 속으로 사라져버렸다.

정적 vs 동적 컨텐츠

CGI를 설명하기 전에, 정적 - 동적 컨테츠에 대한 정의 먼저 확실하고 들어가는 것이 좋을 것 같아 중간에 추가했다.
허구한날 정적이다~ 동적이다~ 하는데, JS 정도면 동적인거 아냐? 사용자 입력에 반응하잖아! 라고 생각이 종종 들곤한다.
웹 서버란 무엇일까? - MDN web docs
그러나 위 문서에서 설명하고 있듯이, 정적 - 동적을 나누는 기준은 "있는 그대로 제공되는 것(served as-is)"을 말한다.
즉, 이미 완성된 형태로 존재하는 HTML, 이미지 파일, CSS, JS 등이 모두 정적 콘텐츠 라는 것이다.

그럼 동적 콘텐츠는 뭐가 다를까?
Web Application 내부에 존재하는 비즈니스 로직, 더 나아가 그와 상호작용하는 DB를 통해 "생성된 콘텐츠"를 의미한다.
예를 들면, 어떤 커뮤니티 사이트에서 부여된 권한에 따라 동일한 페이지에 보여지는 것이 다른 경우가 있다.
분명 같은 URL을 통해 요청했을텐데 더 높은 권한이 있는 사람들에게는 설정버튼도 글 삭제 버튼도 추가로 보일 것이다.
바로 이것이 "동적"이다. 라는 의미이다.

CGI (Common Gateway Interface)

Java Applet이 Client-side 동작을 위탁하는 방식이지만, CGI는 반대로 Server-side에서 동적 콘텐츠를 제공하기 위한 동작을 담당한다.
W3C의 CGI 공식문서를 보면 아래와 같이 설명하고 있다.

HTTP 서버는 종종 기존 정보 시스템(예: 기존 문서 모음이나 기존 데이터베이스 애플리케이션)으로의 게이트웨이 역할을 합니다. 공통 게이트웨이 인터페이스(Common Gateway Interface, CGI)는 이러한 게이트웨이 스크립트와 프로그램을 통합하는 방법에 대해 HTTP 서버 구현자들 간의 합의입니다.
CGI는 일반적으로 HTML 폼과 함께 사용되어 데이터베이스 애플리케이션을 구축하는 데 활용됩니다.

여기서 확실히 집고 넘어갈 부분은 CGI(Common Gateway Interface)는 Interface, 표준이자 합의이며 스크립트로 작성된다는 정보이다.

그럼 어떤 식으로 동작되게 정의도어 있는 것일까? 우선 아래의 이미지를 보며 시작하자
CGI 동작 이미지

  1. 서버의 cgi-bin이라는 폴더를 만들어놓고, 그 내부의 스크립트 파일을 만들어놓는다.
  2. 사용자가 웹서버에 요청을 보내면, 웹 서버는 CGI를 통해 cgi bin에 접속해서 그 내부의 스크립트 파일을 실행시키고, 그 결과를 클라이언트에 보낸다.

현재 서버들과 비교하자면, Django, Spring 등의 WAS들이 서비스 단에서 하고 있는 작업을 CGI에서는 스크립트 파일로 했다는 것이다.
(여기서 말하는 스크립트 파일은 리눅스에서 종종 사용하던 Shell Script 파일과 유사하다.)

여기까지 들으면 이 방식의 문제점이 보이기 시작한다.

  1. 플랫폼 의존성 - CGI 스크립트는 C, Perl, Python, Shell 스크립트 등의 언어로 작성될 수 있었는데, 이는 이를 실행할 수 있는 컴파일러나 운영체제에 의존한다.
  2. 확장성 부족 - 스크립트로 작성된 파일인 만큼, 다른 언어에 비해 확장하기가 어렵다.
  3. 성능 문제 - 요청 1개당 프로세스를 1개를 실행해야했다. 이는 스크립트언어가 코드를 실행할 때마다 해석되는 특성을 가지고 있기 때문이다.

이런 이유들 때문에 CGI는 현재에 들어서는 거의 쓰이지 않는 추세이다.

Java Servlet

Java 공식 문서에서는 Java Servlet에 대해 다음과 같이 설명한다.

Servlet은 서버의 기능을 확장하기 위해 Java 프로그래밍 언어로 작성된 클래스입니다. Servlet은 request-response programming model을 통해 애플리케이션에 접근하는 서버에서 사용됩니다. Servlet은 어떤 유형의 요청에도 응답할 수 있지만, 주로 웹 서버가 호스팅하는 애플리케이션을 확장하는 데 사용됩니다. 이러한 애플리케이션을 위해 Java Servlet 기술은 HTTP에 특화된 Servlet 클래스를 정의합니다.
Servlet을 작성하기 위해서는 javax.servlet 및 javax.servlet.http 패키지가 제공하는 인터페이스와 클래스를 사용합니다. 모든 Servlet은 Servlet 인터페이스를 구현해야 하며, 이 인터페이스는 Servlet의 생명 주기 메서드를 정의합니다. 일반적인 서비스를 구현할 때는 Java Servlet API와 함께 제공되는 GenericServlet 클래스를 사용하거나 확장할 수 있습니다. HttpServlet 클래스는 HTTP 특화 서비스를 처리하기 위한 doGet 및 doPost와 같은 메서드를 제공합니다.

위에 중요한 키워드를 뽑아보면 아래와 같다.

  1. request-response programming model
  2. 웹 서버가 호스팅하는 애플리케이션을 확장하는 데 사용
  3. 모든 Servlet은 Servlet 인터페이스를 구현해야 하며, 이 인터페이스는 Servlet의 생명 주기 메서드를 정의해야한다.

2번부터 설명하자면, 웹 서버, 기존에 정적 콘텐츠를 제공하던 서버가 호스팅하는 애플리케이션(비즈니스 로직 등, 동적 콘텐츠를 생성할 수 있는 애플리케이션이 들어있는 곳)을 확장하는데 사용한다는 의미이다.

3번에서는 모든 Servlet이 결국 인터페이스이며 명확한 구현체가 있지 않다는 것이다.
즉, 큰 뼈대를 통해 이런이런 기능은 구현할 수 있고, 이런 생명 주기를 가져야한다! 만 정의해 두고 구현에 따라 얼마든지 동작이 달라질 수 있다는 것이다.
아래는 Servlet 인터페이스 공식문서에서 가져온 정의해야될 메서드 목록이다.

일반적으로 처음 실행될 때 Servlet 인스턴스가 존재하지 않으면 Web Container는 Servlet 클래스를 로드하여 init 메서드를 실행하고, 특별한 일이 없으면 이를 서버 종료까지 유지하며 재사용한다. (싱글톤 패턴 처럼)
이후 service 메서드를 실행해 1개의 요청을 처리하고 응답을 수정한다.
destroy()는 서버 종료, Servlet 종료, Web Container의 재시작 같은 작업에서만 실행되며, 여기에 연결되거나 할당된 자원들을 해제하는 역학을 한다.

1번에서는 request-response programming model이라는 말을 한다.
즉, request를 처리하고 response를 수정한다는 말이다.
그럼 여기서 Spring 사용자(다른 프레임워크는 몰라서..ㅎ)는 의문이 들 수 있다.
"?? Controller랑 Servlet이랑 뭐가 다른거임?, 그냥 Controller에서 하는일을 Servlet에 통합해버리면 되잖아!"
답은 의외로 간단하게, 기본적인 프로그래밍의 원칙에 있다. 책임을 분리한 것이다.
Servlet은 이미 많은 작업을 담당하고 있고, 거기에 Controller가 담당하고 있는 데이터 바인딩 및 검증, 비즈니스 로직, 매핑 등의 작업이 추가로 들어간다 생각해보자, 심지어 url 별로!
이는 끔찍하게 복잡하고, 긴 코드가 될 것이다.

이외에도 Servlet으로 처리할 수 있는 일은 많다.
공식문서를 보면 필터링, 세션, 웹 리소스 호출 등등...
근데 여기서 다루기엔 내용이 너무 방대하니 가능하다면, 직접 공식문서에 들어가 읽어보는 것을 추천한다.

마무리

이 글은 사실상 지난날에 분풀이에 가깝다.
이전에 Servlet은 뭐고 Controller랑 뭐가 다른지에 대해 질문을 받은 적이 있었는데, 꿀먹은 벙어리 마냥 버벅거리면서 아무말도 못했었다...ㅎ
명색에 Spring을 써봤다는 놈이 그것도 몰랐다는 것에 충격이었고, 블로그마다 설명하는 내용이 제각각인 것도 충격이었다.

그래서 이 글은 이 개념에 대한 나만의 기준을 세우기 위해 작성한 것이다. 누구에게라도 Servlet에 대해 물어보면, 나는 이러이러하게 생각한다. 자신을 가지고 답변할 수 있게끔
물론 이에 틀린 내용이 있을 수 있으니 그에 대한 지적은 언제든 환영 ㅎ

레퍼런스

0개의 댓글