[Spring, Web] 서블릿(Servlet)

344th·2024년 2월 11일

Develop

목록 보기
4/8

JSP/Servlet이 SSR 방식이다.

서블릿(Servlet)

서블릿(Servlet)이란 동적 웹 페이지를 만들 때 사용되는 자바 기반의 웹 애플리케이션 프로그래밍 기술이다. 서블릿은 웹 요청과 응답의 흐름을 간단한 메서드 호출만으로 체계적으로 다룰 수 있게 해준다.

  • 클라이언트의 요청을 처리하고 결과를 반환하는 Servlet 클래스의 규칙을 지킨 자바 웹 프로그래밍 기술
  • 자바를 사용하여 웹을 만들기 위해 필요한 기술 (자바 기반 --> JDK / JVM 필수)

: 즉, java를 이용해 웹개발을 하기 위해서 필요한 가장 기본적인(low한) 기술이 Servlet

  • 좁게 보면 서블릿이란 위와 같은 기능을 하는 자바의 클래스,
  • 넓게 보면 위 기능을 수행하기 위한 자바의 패키지를 뜻한다.
  • 서블릿은 자바 언어로 쓰여지고 자바를 기반으로 하는 프로그램
    • 이러한 서블릿 클래스는 javax.servlet.http(jakarta.servlet.http) 라는 패키지 안에 포함
    • javax.servlet(=jakarta.servlet) 패키지: 서블릿 구현을 위한 다양한 인터페이스와 클래스가 포함된 꾸러미

서블릿(Servlet)의 특징

  • 클라이언트의 Request에 대해 동적으로 작동하는 웹 애플리케이션 컴포넌트
  • 기존의 정적 웹 프로그램의 문제점을 보완하여 동적인 여러 가지 기능을 제공
  • html을 사용하여 요청에 응답
  • Java Thread를 이용하여 동작
  • MVC 패턴에서 Controller로 이용
  • 컨테이너에서 실행
  • 보안 기능을 적용하기 쉬움

서블릿의 동작

웹 구조에서의 서블릿 동작

서블릿 내부 동작

  • Client가 HTTP 요청
  • WASweb.xml을 참조하여 해당 Servlet에 대한 Thread를 생성한다. (Thread Pool 이용)
  • WAS는 요청 URL에 해당되는 서블릿 객체를 호출(서블릿을 지원하는 WAS == 서블릿 컨테이너)
  • WAS는 HttpServletRequest / HttpServletResponse 객체를 생성 후 Servlet에 전달
    • ThreadServletservice() 메서드를 호출한다.
    • service() 메서드는 요청에 맞게 doGet() 또는 doPost() 메서드를 호출한다.
  • 개발자는 HttpServletRequest를 통해 요청 정보를 편리하게 사용
  • ====비즈니스 로직 수행====
  • 개발자는 HttpServletResponse를 통해 응답 정보를 작성
  • WAS는 HttpServletResponse를 통해 HTTP Response Message 생성 후 Client에 전달
  • HttpServletRequest, HttpServletResponse 객체 소멸
    • destroy() 호출

서블릿 패키지 내 구조

우리가 흔히 사용하는 서블릿  클래스를 불러오면 다음과 같은 코드로 되어있다.

public class Test extends HttpServlet {
	private static final long serialVersionUID = 1L;

    public Test() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

우리가 사용하는 서블릿은 HttpServlet을 상속받아 구현한다.
서블릿 클래스는 실은 javax.servlet(=jakarta.servlet) 패키지의 일부이다.

❓ 그렇다면 서블릿 클래스를 사용하기까지 구조는 어떻게 될까?

우리가 상속받아 만드는 HttpServlet 클래스의 패키지내 구조는 위와 같다.

간단히 각 인터페이스에 대해 설명하면 다음과 같다.

1. Servlet 인터페이스

각종 서블릿 클래스를 구현하는 가장 기본 토대가 되는 인터페이스

  • 해당 인터페이스를 구현하면 서블릿 클래스를 구현하여 사용할 수 있다.
  • 해당 인터페이스를 구현하기 위해서는 아래 5개의 메서드(생명주기 메서드)를 구현해야 한다.

(1) init()

웹 컨테이너에 의해 호출되어 서블릿이 서비스에 위치할 수 있도록 초기화하는 메서드

  • 웹 컨테이너는 서블릿 객체를 생성하며, 서블릿 생명 주기 중 단 한번 init() 메서드를 호출한다.
  • 즉 서블릿 객체 생성 이후에 서블릿의 초기화는 단 한번만 이뤄진다는 것이다.
  • 서블릿은 init() 메소드가 완료되어야 서비스에 배치가 가능하다.
  • 이때 초기화 중 필요한 정보는 ServletConfig 인터페이스 타입의 객체를 매개변수로 받는다.
  • 일반적으로 클라이언트가 서블릿을 처음 요청할 때 호출된다.
    • 설정으로 요청 없이 서버 시작시 서블릿을 로드하고 init() 메서드를 호출할 수도 있다.

(2) service()

웹 컨테이너에 의해 호출되어 서블릿이 클라이언트의 요청에 응답할 수 있도록 하는 메서드

  • service() 메서드는 init() 메서드가 성공적으로 실행된 이후 호출이 가능하다.
  • 클라이언트의 요청을 전달하는 ServletRequest 객체를 통해 웹 컨테이너에 정보가 전달되면 service() 메서드가 실행되고 service() 메서드는 요청에 따른 메서드를 실행한다.
    • 예: doGet, doPost, doPut, doDelete
  • 그 후 실행에 따른 결과물을 클라이언트에게 요청을 전달하는 ServletResponse로 응답한다.
  • 한 가지 서블릿에 대해 다중 요청이 들어와도 서블릿을 매번 로드하고 초기화하지 않는다.
    • 서블릿은 한번 불러왔다면 초기화는 더이상 수행되지 않는다.
    • 사용자 요청이 있으면 웹 컨테이너는 사용자의 요청에 맞춰 스레드를 만든다.
    • 그 스레드를 통해서 service 메서드를 실행하고 이미 초기화가 끝나 대기중인 서블릿을 실행한다.

(3) destroy()

웹 컨테이너에 의해 호출되어 수명이 다한 서블릿을 서비스에서 제외되도록 하는 메서드

  • 일반적으로 개발자가 아닌 웹 컨테이너에 의해 자동으로 수행된다.
  • 이 또한 init() 메서드와 같이 단 한번만 실행된다.
    • 만약 서버를 끄거나 재시작할 경우에도 해당 메서드가 실행된다.

(4) getServletConfig()

서블릿의 초기화를 위한 정보를 포함하는 ServletConfig의 객체를 반환하는 메서드

  • 참고로 이때 반환되는 객체는 이미 한번 init() 메서드로 전달된 상태의 객체다.

(5) getServletinfo()

서블릿에 관한 다양한 정보(버전, 저작권자, 작성자)를 반환한다.

2. ServletConfig 인터페이스

초기화 중에 서블릿에 정보를 전달하기 위해 서블릿 컨테이너에서 사용하는 서블릿 구성을 위한 객체

3. GenericServlet 추상 클래스

Servlet 인터페이스와 ServletConfig 인터페이스를 구현하여 만든 추상 클래스

  • 기존 Servlet 인터페이스를 구현하기 위해서는 일일이 메서드를 따로 만들어줘야했다.
  • 게다가 ServletConfig 인터페이스까지 같이 구현해야 했다.

이를 조금 더 수월하게 하기 위해 만든 것이 GenericServlet 추상 클래스다.

  • GenericServletServlet의 라이프사이클 메서드 중 init(), destroy()를 간단하게 제공한다.

즉 사용자는 service()만 구현하여 서블릿을 간편하게 실행할 수 있다.

4. HttpServlet 추상 클래스

GenericServlet를 상속하여 만든 추상 클래스

  • HttpServletGenericServlet과 마찬가지로 상속받으면 간단하게 서블릿을 실행할 수 있다.
  • 우리가 대부분 사용하는 서블릿은 HttpServlet 추상 클래스를 상속받은 클래스이다.
  • HttpServletinit(), destroy()까지 구현했다면 HttpServletservice()까지 구현되어있다.
  • 설정상으로는 건드릴 필요가 없을 정도로 구체화 정도가 높은 편이다.
  • 다만 이름에서 알 수 있듯이 GenericServletHTTP뿐 아니라 다양한 프로토콜에 대응이 가능하다.
  • GenericServletHTTP 프로토콜을 이용하지 않을 때도 사용이 가능하다.
  • HttpServletHTTP 프로토콜에만 한정적으로 사용할 수 있다.
    • HttpServlet는 웹 개발에서 주로 쓰는 프로토콜이 HTTP기 때문에 이를 위함

주의

HttpServlet가 상속받는 GenericServlet는 javax.servlet(jakarta.servlet)의 패키지다.

하지만 우리가 흔히 쓰는 서블릿 클래스는 HttpServlet을 상속받는데,
이 추상클래스는 HTTP 프로토콜 대응을 위한 서블릿 전용 패키지인 javax.servlet.http(jakarta.sevlet.http) 패키지에 속해있다.

서블릿의 생명주기

서블릿도 자바 클래스이므로 실행하면 초기화부터 서비스 수행 후 소멸하기까지의 과정을 거친다. 이 과정을 서블릿의 생명주기라하며 각 단계마다 호출되어 기능을 수행하는 콜백 메서드를 서블릿 생명주기 메서드라한다.

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

서블릿 생명주기 메서드

초기화 : init()

서블릿 요청 시 맨 처음 한 번만 호출된다.
서블릿 생성 시 초기화 작업을 주로 수행한다.

  • 서블릿은 init() 메소드가 완료되어야 서비스에 배치가 가능하다.
  • 이때 초기화 중 필요한 정보는 ServletConfig 인터페이스 타입의 객체를 매개변수로 받는다.
  • init() 메서드는 일반적으로 클라이언트가 서블릿을 처음 요청할 때 호출된다.
    • 하지만 설정으로 요청 없이 서버 시작시 서블릿을 로드하고 init() 메서드를 호출할 수도 있다.

작업 수행 : service()

웹 컨테이너에 의해 호출되어 서블릿이 클라이언트의 요청에 응답할 수 있도록 하는 메서드

  • 서블릿 요청 시 매번 호출된다.
  • 실제로 클라이언트가 요청하는 작업을 수행한다.
  • service() 메서드는 init() 메서드가 성공적으로 실행된 이후 호출이 가능하다.
  • 클라이언트의 요청을 전달하는 ServletRequest 객체를 통해 웹 컨테이너에 정보가 전달되면
    service() 메서드가 실행되고 service() 메서드는 요청에 따른 메서드(doGet, doPost, doPut, doDelete)를 실행한다.
    그 후 실행에 따른 결과물을 클라이언트에게 요청을 전달하는 ServletResponse로 응답한다.

종료 : destroy()

웹 컨테이너에 의해 호출되어 수명이 다한 서블릿을 서비스에서 제외되도록 하는 메서드

  • 서블릿이 기능을 수행하고 메모리에서 소멸될 때 호출된다.
  • 서블릿의 마무리 작업을 주로 수행한다.
  • init() 메서드와 같이 단 한번만 실행된다.
    • 만약 서버를 끄거나 재시작할 경우에도 해당 메서드가 실행된다.

Parameter 전송방식

GET 방식

서블릿 컨테이너

  • 서블릿을 관리하기 위한 모든 작업을 수행 (생성 / 호출 / 관리)
  • java thread를 사용해서 서블릿을 호출
  • 톰캣(Tomcat)처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 함
  • 서블릿 객체는 싱글톤으로 관리
    • 고객의 요청이 올 때 마다 생성하는것은 비효율적이기 때문
    • 공유 변수 사용에 주의해야 한다
    • 서블릿 컨테이너가 종료 --> 서블릿도 종료
  • 동시 요청을 위한 멀티 쓰레드(Multi Thread) 처리를 지원

  • 실제 우리가 WAS를 직접 구현하면 많은 사전 과정을 구현해야 한다
    • TCP/IP 연결 & 소켓 연결
    • HTTP request 메시지 파싱
    • HTTP response 메시지 작성
    • TCP/IP 및 소켓 연결 종료
  • Servlet을 지원하는 WAS 즉, 서블릿 컨테이너는 이러한 과정들을 대신 수행해준다 개발자는 비즈니스 로직에 집중할 수 있다!

서블릿 작성 예시

public class myServlet extends HttpServlet {

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init method 호출!");
    }
    
    @Override
    public void destroy() {
        System.out.println("destroy method 호출!");
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        System.out.println("doGet service method 호출!");		
    }
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        System.out.println("doPost service method 호출!");		
    }
	
}

서블릿 설정 파일 (web.xml)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">
 
     <servlet> //서블릿 클래스를 서블릿으로 등록
           <servlet-name>myServlet</servlet-name> //해당 서블릿을 참조할 때 사용할 이름
           <servlet-class>controller.MyServlet</servlet-class> //서블릿으로 사용할 서블릿 클래스의 FullName
     </servlet>
 
     <servlet-mapping>
           <servlet-name>myServlet</servlet-name> //매핑할 서블릿의 이름
           <url-pattern>/myServlet</url-pattern> //매핑할 URL 패턴
     </servlet-mapping>
 
</web-app>

서블릿을 작성하였다면 해당 서블릿을 사용자가 요청한 경로와 맵핑시켜줘야 WAS에서 맵핑된 정보를 읽어서 브라우저에서 해당 URLHTTP 요청 시 해당 서블릿으로 요청을 전달해 줄 수 있다. 소스를 분석할 때도 가장 먼저 확인해봐야 할 부분이다. 톰캣을 예로 들자면 웹 애플리케이션 서비스 처리에 대한 정의된 환경 설정 파일이 server 디렉터리web.xml에 있다.

JSP(Java Server Page)

Java 코드가 들어가 있는 HTML 코드

  • 서블릿은 자바 소스코드 속에 HTML코드가 들어가는 형태
  • JSP는 이와 반대로 HTML 소스코드 속에 자바 소스코드가 들어가는 구조를 갖는 웹어플리케이션 프로그래밍 기술
  • HTML속에서 자바코드는 <% 소스코드 %> 또는 <%= 소스코드 =%>형태로 들어간다.
  • 자바 소스코드로 작성된 이 부분은 웹 브라우저로 보내는 것이 아니라 웹 서버에서 실행되는 부분이다.
  • 웹 프로그래머가 소스코드를 수정 할 경우에도 디자인 부분을 제외하고 자바 소스코드만 수정하면 되기에 효율을 높여준다.
  • 또한 컴파일과 같은 과정을 할 필요없이 JSP 페이지를 작성하여 웹 서버의 디렉토리에 추가만 하면 사용이 가능하다.
  • 서블릿 규칙은 꽤나 복집하기 때문에 JSP가 나오게 되었는데, JSP는 WAS(Web Application Server)에 의하여 서블릿 클래스로 변환하여 사용되어진다.

JSP 동작

  • 웹 서버가 사용자로부터 서블릿에 대한 요청을 받으면 서블릿 컨테이너에 그 요청을 넘긴다.
  • 요청을 받은 컨테이너HTTP RequestHTTP Response 객체를 만들어, 이들을 통해 서블릿 doPost()doGet() 메소드(service() 메소드) 중 하나를 호출한다.
  • 만약 서블릿만 사용하여 사용자가 요청한 웹 페이지를 보여주려면 out 객체의 println 메소드를 사용하여 HTML 문서를 작성해야 하는데 이는 추가/수정을 어렵게 하고, 가독성도 떨어지기 때문에 JSP를 사용하여 비지니스 로직과 프레젠테이션 로직을 분리한다.
  • 여기서 서블릿은 데이터의 입력, 수정 등에 대한 제어를 JSP에게 넘겨서 프레젠테이션 로직을 수행한 후 컨테이너에게 Response를 전달한다.
  • 이렇게 만들어진 결과물은 사용자가 해당 페이지를 요청하면 컴파일이 되어 자바파일(.java)을 통해 .class 파일이 만들어지고, 두 로직이 결합되어 클래스화 되는것을 확인할 수 있다.
  • 즉, out객체의 println 메소드를 사용해서 구현해야하는 번거로움을 JSP가 대신 수행해준다.

MultiThread(멀티 쓰레드) / Thread Pool(쓰레드 풀)

MultiThread(멀티 쓰레드)

  • 서블릿 컨테이너는 쓰레드(Thread)를 사용해서 서블릿(Servlet)을 호출
  • 여러개의 쓰레드를 사용해서 다중 요청을 효율적으로 처리하는 방법
  • 요청이 올 때 마다 쓰레드를 생성하면 치명적인 문제점이 있다
    • 쓰레드 생성의 제한이 없음-> 고객 요청이 많으면 CPU, 메모리 임계점을 넘어서 서버가 죽는다
    • 쓰레드의 생성 비용이 요청 시 마다 계속 필요
    • 이러한 단점을 극복하기 위한 방법이 바로 쓰레드 풀

Thread Pool(쓰레드 풀)

  • 필요한 쓰레드의 개수를 정해놓고 미리 생성해둔 뒤 사용하고 반납하여 비용을 줄이는 방식
  • 톰캣은 최대 200개의 쓰레드풀로 기본 설정
  • 최대 쓰레드가 모두 사용중이면 요청은 대기 / 거절 선택
  • 장점
    • 쓰레드의 생성에 대한 비용이 줄어든다
    • 생성 가능 쓰레드의 최대치가 존재해서 요청을 안전하게 처리할 수 있다 -> 서버가 죽지 않음

**멀티 쓰레드(Multi Thread)에 대한 부분은 WAS가 처리**

  • 개발자는 멀티 쓰레드 관련 코드를 신경쓰지 않아도 된다.
  • 하지만 멀티 쓰레드 환경이라는 것을 인지하고 싱글톤 객체를 주의해서 사용해야 한다.

참조

  1. https://velog.io/@falling_star3/Tomcat-서블릿Servlet이란
  2. https://coding-factory.tistory.com/742
  3. https://sgcomputer.tistory.com/226
  4. https://java-is-happy-things.tistory.com/23
  5. https://java-is-happy-things.tistory.com/23
profile
새싹 개발자

0개의 댓글