Closed emiling closed 2 years ago
서블릿은 JavaEE에 종속된 기술로, JavaEE docs에서 그 정의를 살펴보면 다음과 같습니다.
A servlet is a Java programming language class that is used to extend the capabilities of servers that host applications accessed by means of a request-response programming model.
서버의 기능을 확장한다
는 말이 조금 난해한데, 추측상 다양한 요청을 처리하는 것을 서블릿이 제공하는 인터페이스를 통해 선언적인 방식으로 구현할 수 있다는 말로 이해했습니다.
서블릿은 모든 타입의 요청에 응답할 수 있지만, 일반적으로 웹 서버에서 호스팅하는 애플리케이션을 확장하는 데 사용된다고 합니다. 그래서 서블릿을 좁은 의미로 설명할 때, 자바 기반의 동적 웹 페이지를 제공하기 위한 기술이라고 설명하기도 합니다.
서블릿을 작성하기 위해서, javax.servlet과 javax.servlet.http에서 제공하는 클래스나 인터페이스를 상속해야 합니다.
HTTP 기반이 아닌 일반 서비스 구현을 위해서는 GenericServlet
클래스를 확장하고,
HTTP 기반의 서비스를 구현하기 위해서는 GenericServlet
을 확장한 HttpServlet
클래스를 확장합니다.
HttpServlet은 서블릿의 기능에 HTTP와 관련한 메서드, 이를테면 doGet
, doPost
의 메소드 등을 제공합니다.
/* GenericServlet.java */
/* 주로 서블릿의 생명주기 관리 메서드를 작성 */
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
...
public void destroy() {
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
/* HttpServlet.java */
/* Http 관련 기능을 확장한 Servlet */
public abstract class HttpServlet extends GenericServlet {
...
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_get_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
...
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_post_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_put_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
...
}
서블릿을 통해, 웹 서버가 클라이언트 요청을 처리하는 과정을 요약하면 다음과 같습니다.
HttpServletRequest
, HttpServletResponse
객체 생성web.xml
에 정의된 url pattern을 확인하고, 요청을 처리할 서블릿 검색 or 생성요약하면, HTTP 요청마다 요청을 처리할 서블릿을 생성하고, 생성한 서블릿을 요청에 맵핑하여 HTTP Request를 처리하는 Actor
로 사용합니다.
앞서 말했듯, Servlet Container는 Http 요청과 Servlet을 맵핑하여 처리합니다. 그래서 JavaEE
등의 레거시에서는 Servlet 인터페이스의 구현체를 만들어 사용했으나, 스프링 MVC에서는 Dispatcher Servlet
이라는 서블릿을 통해 요청을 수신하고, 적당한 Controller Layer(ex. Controller- Service - DAO)를 검색하여 비즈니스 로직을 처리한 후 결과를 반환하는 형태로 요청을 처리합니다. 이러한 방식을, FrontController 패턴
이라고 부릅니다.
스프링 MVC의 DispatcherServlet이 Servlet 구현의 책임을 가져가고, 개발자에게는 서블릿이 아닌 스프링 컨텍스트 작성
의 책임을 주었기 때문에, 기존 JavaEE에 종속된 프로그램을 만들어야 했던 패턴을 벗어나 지금의 POJO 지향 프로그램 개발이 가능했다고 생각되네요.
그럼, DispatcherServlet이 Servlet Container와 Spring Container를 어떻게 연결하는지 궁금해집니다. DispatcherServlet은 Servlet Container에 포함된 개념이기 때문에, DispatcherServlet에서 Spring Container를 참조할 수 있기만 한다면, 두 개의 연결이 성립한다고 볼 수 있겠습니다.
Spring Container란, 사실상 ApplicationContext
를 의미한다고 볼 수 있죠. 다시 말해, Spring Container를 참조할 수 있다는 것은 ApplicationContext를 알고 있다는 것이고, 이러한 맥락에서 이전에 보았던 ApplicationContextAware
를 떠올릴 수 있습니다.
코드 수준에서 이를 살펴보도록 하겠습니다.
public class DispatcherServlet extends FrameworkServlet {
...
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
this.setDispatchOptionsRequest(true);
}
...
}
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
...
}
DispatcherServlet의 계층구조를 보면, DispatcherServlet ApplicationContextAware
를 구현하고 있고, 생성자 주입을 통해 WebApplicationContext
를 주입받는 것을 알 수 있습니다.
이러한 방식으로, Servlet Container와 Spring Container는 연결되어 작동합니다.
질문
Springboot에서 servlet을 resolving 하는 원리가 궁금합니다
상세 내용
추가적으로 Servlet 컨테이너가 하는 역할은 무엇인지와 Servlet의 작동 원리와 관련하여 한 번 생각해보면 좋을 듯 합니다
연관 챕터
참고
35