반응형
Servlet
서블릿은 자바를 기반으로 한 웹 어플리케이션 개발 기술로, 클라이언트의 요청과 응답을 처리하고 동적인 콘텐츠를 생성하는 역할을 담당합니다.
Servlet의 역할
앞서 포스팅한 웹 서버 vs 웹 어플리케이션 서버 vs CGI 프로그램: 차이 쉽게 이해하기 에서 서블릿과 서블릿 컨테이너에 관해 간단하게 설명을 했었습니다. 앞에 내용을 안다는 전제하에 설명을 하도록 하겠습니다.
원래는 클라이언트가 데이터를 전송하기 위해서는 소켓 연결, HTTP 요청 메시지 파싱, Content-Type 확인, HTTP 응답 메시지 생성 등 많은 것들을 직접해주어야 했지만 서블릿을 지원하는 WAS(엄밀히 말하면 WAS안에 포함되어 있는 서블릿 컨테이너)를 사용하면서 비즈니스 로직을 제외한 모든 처리를 서블릿이 해줌으로 사용자는 매우 편리해졌습니다.
서블릿 컨테이너가 서블릿에 대해 호출을 하기 위해서는 Servlet 인터페이스(javax.servlet.Servlet 인터페이)로 서블릿 클래스를 정의해주어야합니다.
- init():
서블릿의 생성과 초기화를 담당합니다. 웹 컨테이너에서 서블릿 클래스의 인스턴스를 생성할 때 호출되며, 초기화 작업에 활용됩니다. 서블릿이 클라이언트의 요청을 처리하기 전에 준비할 작업이 있다면 해당 메서드에 작성해주면 됩니다. - service():
클라이언트가 요청할 때 마다 호출되는 메서드입니다. 실질적으로 요청에 대한 작업을 수행하는 메서드로, 이 메서드에 서블릿이 해야 할 일을 작성해주면 됩니다. 클라이언트의 요청 메서드(GET, POST 등)에 따라 적절한 메서드(`doGet(), `doPost()` 등)를 호출하여 요청을 처리하고 응답을 생성합니다. - destory():
서블릿의 생명 주기 중 종료 단계를 담당합니다. 서블릿 컨테이너가 종료되거나, 서블릿이 더 이상 필요하지 않을 때 호출됩니다. 서블릿의 마무리 작업을 수행하는데 활용됩니다.
- getServletConfig():
서블릿 설정 정보를 다루는 ServletConfig 객체를 반환합니다. 이 객체는 서블릿 이름과, 서블릿 초기 매개변수 값, 서블릿 환경 정보가 담겨있습니다. - getServletInfo():
서블릿을 작성한 유저의 대한 정보, 서블릿 버전 권리 등을 담은 문자열을 반환합니다.
💁 service(), doGet() , doPost() ??
`service()` 대신에 `doGet()`이나 `doPost()`메서드를 사용한 예제를 더 많이 봤을 것입니다.
`Servlet` 인터페이스는 서블릿 컨테이너가 서블릿을 관리하고 실행하기 위한 메서드들을 정의하고 있습니다. 그리고 `HttpServlet` 클래스는 `Servlet` 인터페이스를 상속받아서 이를 확장한 클래스로, HTTP 프로토콜을 처리하는 메서드들을 추가로 제공하여 웹 어플리케이션 개발에 특화된 기능들을 제공합니다.
`HttpServlet`을 상속받아 서블릿 클래스를 구현하면 `doGet()`이나 `doPost()`와 같은 메서드를 구현할 수 있고, 이를통해 HTTP GET 또는 POST 요청을 처리할 수 있는 서블릿을 개발할 수 있습니다.
💁 Servlet, GenericServlet, HttpServlet ??
서블릿 클래스를 만들 때 Servlet 인터페이스를 반드시 구현해야합니다. 인터페이스를 구현하기 위해서 인터페이스 내에 선언된 메서드인 init(), service(), destroy(), getServletConfig(), getServletInfo()를 모두 구현해주어야 합니다.
`service()` 메서드는 실질적인 작업이 이루어지는 메서드이기 때문에 반드시 구현해주어야 하지만, 다른 메서드들은 상황에 따라 구현할 필요가 없습니다. 때문에 빈 메서드라도 구현을 해주어야 하는데 이런 번거로움을 줄여주는 는것이 바로 `GenericServlet 추상 클래스`입니다. 무조건 구현해주어야 하는 service()메서드를 제외하고 나머지를 미리 구현하여 상속해주는추상 클래스입니다.
`HttpServlet`은 `GenericServlet` 클래스를 확장한 클래스입니다. HTTP 프로토콜을 사용하는 웹 브라우저에서 서블릿 기능을 수행합니다. `HttpServlet`을 상속받아 사용하면 `service()` 메서드를 작성하는게 아닌 `doGet()`이나 `doPost()`를 작성해주어야 합니다. 클라이언트의 요청이 들어오면 내부적으로는 HttpServlet의 service() 메서드가 호출되고 service() 메서드가 클라이언트 요청 방식(GET, POST, ...)에 따라 doGet(), doPost() 등의 메서드를 호출합니다.
서블릿 작성
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) {
//애플리케이션 로직
}
}
- @WebServlet의 urlPatterns을 지정하여 URL을 매핑합니다.
- init(), service(), destroy()를 재정의(오버라이딩)해주면 됩니다.
- HTTP 요청 정보를 사용할 수 있는 HttpServletRequest 객체, HTTP 응답 정보를 사용할 수 있는 HttpServletResponse 객체를 활용할 수 있습니다.
서블릿 배치 정보
서블릿 컨테이너가 서블릿(Servlet)을 사용하기 위해서는 배치 정보를 알아야 합니다. 이때 배치 정보를 작성하는 방법은 다음과 같이 두 가지가 있습니다.
1. 배치 설명서 파일(web.xml) 작성
<!--서블릿 선언--> <servlet> <servlet-name>서블릿 별명</servlet-name> <servlet-class>패키지 경로 포함한 서블릿 파일명</servlet-class> </servlet> <!--서블릿을 URL과 연결--> <servlet-mapping> <servlet-name>서블릿 별명</servlet-name> <url-pattern>/URL이름</url-pattern> </servlet-mapping> <!--welcome 파일--> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list>
2. `@WebServlet` 작성
Servlet 3.0 버전부터 어노테이션을 통해 서블릿 배치 정보를 작성할 수 있습니다. 이때 위 예제 코드 처럼 서블릿 클래스 내부에 배치 정보를 작성해주면 됩니다.
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
서블릿 동작 절차
- 클라이언트의 요청이 들어오면 서블릿 컨테이너는 서블릿을 찾습니다.
이때 서블릿 배치 정보 파일(web.xml) 혹은 `@WebServlet` 어노테이션으로 찾습니다. - 웹 어플리케이션 서버(WAS)는 request, response 객체를 새로 만들어서 서블릿 객체를 호출합니다.
- 만약 서블릿 인스턴스가 없다면, 서블릿 클래스를 로딩하고 인스턴스를 준비한 후 생성자를 호출합니다. 그리고 서블릿 초기화 메서드인 `init()`을 호출합니다.
- 클라이언트 요청을 처리하는 `service()`메서드를 호출합니다. (`doGet()` or `doPost()` 메서드)
- 웹 어플리케이션을 종료하거나 서블릿 컨테이너가 종료 호출이 오면 서블릿 컨테이너는 종료되기 전에 서블릿이 마무리 작업을 수행할 수 있도록 생성된 모든 서블릿에 대해 `destroy()` 메서드를 호출합니다.
서블릿 컨테이너 특징
- Tomcat 처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 합니다.
- 서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 종료하는 생명 주기를 관리합니다.
- 이때 위 이미지에서 보듯이, 서블릿 객체는 `싱글톤`으로 관리됩니다. 때문에 모든 요청은 동일한 서블릿 객체 인스턴스에 접근하므로 공유 변수 사용시 주의해주어야 합니다.
- request와 response 객체는 항상 새로 생성하여 사용합니다.
- 동시 요청을 위한 `멀티 스레드` 처리를 지원합니다.
WAS `멀티 스레드` 지원
`스레드`란 프로세스의 실행 단위입니다.
클라이언트의 요청(request)이 들어오면 WAS는 서블릿 호출 및 수행을 위해 스레드를 한 개 할당합니다. 해당 요청을 처리하고 있는 중에 다른 요청이 들어오게 되면 단일 스레드인 경우 지연되지만, 멀티 스레드인 경우 새로운 스레드를 생성하여 할당하는 것으로 요청을 처리합니다.
하지만 스레드의 생성 비용은 비싸고, 컨텍스트 스위칭 비용도 발생하게 됩니다. 이러한 문제를 해결하기 위해 `스레드 풀`을 사용합니다. 스레드를 미리 만들어 스레드 풀에 넣어놓고, 요청이 들어오면 스레드를 사용하게 하고 반납 받는 형식입니다. 이러한 방식으로 스레드를 생성하고 종료하는 비용이 절감되고, 수가 정해져 있기 때문에 많은 요청이 들어와도 안전하게 처리 가능합니다. 스레드 풀에 넣어둘 스레드 수는 CPU, 로직 등을 고려하여 정해주어야 합니다. (Tomcat은 최대 200개)
WAS는 멀티 스레드를 지원하기 때문에 개발자가 멀티 스레드 관련한 코드를 신경쓰지 않고 코드 개발할 수 있도록 해줍니다. 단, 멀티 스레드 환경이기 때문에 싱글톤 객체(Servlet 객체, Bean)는 주의하여 사용해야 합니다.
HttpServletRequest와 HttpServletResponse
서블릿 컨테이너에서 서블릿 객체를 호출할 때 생성되는 request 객체와 response 객체는 보통 HttpServletRequest와 HttpServletResponse의 인스턴스입니다. 이것들은 서블릿 스펙(Java Servlet API)에서 정의된 표준 클래스입니다.
HttpServletRequest와 HttpServletResponse를 통해 HTTP 요청과 응답을 편리하게 처리할 수 있습니다.
HttpServletRequest:
- HTTP 메서드, URL, 헤더 정보, 파라미터, 쿠키, 세션 등을 포함합니다.
- 파라미터 처리:
- getParameter(String name): 파라미터의 값 반환
- getParameterMap(): 모든 파라미터와 값을 맵 형태로 반환
- getParameterNames(): 모든 파라미터의 이름 반환
- 헤더 처리:
- getHeader(String name): 지정된 이름의 HTTP 헤더 값 반환
- getHeaders(String name): 지정된 이름의 HTTP 헤더의 모든 값 반환
- 기타 정보 얻기:
- getMethod(): HTTP 요청 메서드(GET, POST, PUT, DELETE 등) 반환
- getRequestURI(): 요청한 URI(Uniform Resource Identifier) 반환
- getContextPath(): 웹 애플리케이션의 컨텍스트 경로(루트 경로) 반환
- getRemoteAddr(): 클라이언트의 IP 주소 반환
- isSecure(): https 사용 유무
- 세션 관리:
- getSession(boolean create): 클라이언트의 세션 반환 create 매개변수를 사용하여 세션이 없는 경우 새로 생성 여부를 지정할 수 있습니다.
- 속성 관리:
- getAttribute(String name): 요청에 저장된 속성(attribute) 값 반환
- setAttribute(String name, Object value): 요청에 속성 값 설정
HttpServletResponse:
- HTTP 응답 상태 코드 및 헤더 설정:
- setStatus(int sc): HTTP 응답 상태 코드를 설정.
- sendError(int sc, String msg): HTTP 오류 응답 전송.
- setHeader(String name, String value): 응답 헤더를 설정.
- addHeader(String name, String value): 응답 헤더에 새로운 헤더 값을 추가.
- 컨텐츠 타입 및 길이 설정:
- setContentType(String type): 응답의 컨텐츠 타입(Content-Type)을 설정.
- setContentLength(int len): 응답의 컨텐츠 길이(Content-Length)를 설정.
- 출력 스트림 제공:
- getWriter(): 응답 본문을 작성하기 위한 `PrintWriter` 객체를 반환. HTML, JSON, XML 등을 생성하는데 사용
- getOutputStream(): 응답 본문을 작성하기 위한 ServletOutputStream 객체를 반환.
- 리다이렉션:
- sendRedirect(String location): 클라이언트를 다른 페이지로 리디렉션.
- 쿠키 설정 및 삭제:
- addCookie(Cookie cookie): 응답에 쿠키를 추가.
- deleteCookie(Cookie cookie): 쿠키를 삭제.
- 세션 관리:
- 세션을 관리하기 위한 메서드는 HttpServletRequest에 비해 제한적이지만, 클라이언트의 세션 ID를 얻는 등의 기능을 제공합니다.
반응형
'Web' 카테고리의 다른 글
웹 데이터 저장: 로컬 스토리지, 세션 스토리지, 쿠키 (0) | 2023.09.18 |
---|---|
Jar와 War의 차이(spring initializr packaging) (0) | 2023.09.01 |
웹 서버 vs 웹 어플리케이션 서버 vs CGI 프로그램: 차이 쉽게 이해하기 (0) | 2023.08.31 |
Nginx: 웹 서버와 리버스 프록시의 개념과 용도, 사용법 설명 (0) | 2023.06.28 |
확장성을 위한 Tomcat 클러스터링 구성과 설정 방법 (0) | 2023.06.28 |