목차
- 서블릿 (Servlet)
- 서블릿 컨테이너 (Servlet Container)
- 스프링 MVC의 서블릿 - 디스패처 서블릿
- @Controller와 서블릿은 다른 개념인가?
스프링을 공부하거나 프로젝트를 하다가 문서를 찾아볼 때 항상 Servlet
이라는 단어가 나온다. 대충 이해할 때에는 Controller
의 역할을 해주는 녀석이라고 생각할 수 있다. 이렇게 넘겨짚는 것이 가장 안좋은 학습이고, 이는 틀린 말이다. 이제 자세히 알아보자잇!
Java 기준으로 Servlet에 대해 간단히 얘기하면, request 와 response를 처리하는 클래스이다. 즉, Servlet을 이용해 동적으로 웹페이지를 만들 수도 있고, json 형식으로 데이터를 클라이언트에게 보내줄 수도 있고, database로 전송하는 쿼리를 모아볼 수도 있다.
package javax.servlet;
public interface Servlet {
void init(ServletConfig config) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
위는 javax.servlet.Servlet 인터페이스이다. 여기서 눈여겨볼 메서드들은 init()
, service()
, destroy()
메서드이다.
서블릿은 HTTP 프로토콜에 한정된 기술이 아니다. 스프링 프로젝트에서 말하는 서블릿은 거의
"javax.servlet.http.HttpServlet"
을 말한다. 이는 Servlet 인터페이스를 구현한 구현체 중 하나이다.
즉, HTTP 응답과 요청을 처리하는 서블릿은HttpServlet
이라고 볼 수 있다.
- 단, 서블릿은 인터페이스로 조금 더 범용적인 개념을 담고 있기에 구현체는 사용자가 원하는대로 구현해서 사용하는 경우가 많고, JSP, SpringMVC에서도 이를 상속받아 각각의 기술들을 만들어냈다.
init 메서드는 한 번만 호출되도록 설계되었고, 서블릿의 인스턴스가 존재하지 않는 경우 웹 컨테이너는 다음을 수행합니다.
정상적인 경우라면 init 메서드는 서블릿이 요청을 수신하기 전에 완료되고, 서블릿 컨테이너가 해당 서블릿에 요청을 전달하고 서블릿에서 응답을 만들어 보내게 된다.
만약 init 메서드가 ServletException을 발생시키거나 웹 서버에 의해 정의된 시간 내에 반환되지 않는 경우 서블릿을 서비스에 배치할 수 없게 되고 요청을 정상적으로 위임할 수 없게 된다.
service 메서드
는 요청을 처리하는 핵심 로직을 담당하는 메서드이고, 서블릿의 init() 메서드가 성공적으로 완료된 후에만 호출된다.
서블릿 컨테이너는 클라이언트에서 오는 요청을 처리하기 위해 service() 메서드
를 호출하고 HTTP 요청 유형(GET, POST, PUT, DELETE 등)을 해석하고 doGet, doPost, doPut, doDelete 등의 메서드 를 적절하게 호출한다.
destroy 메서드
는 서블릿을 서비스에서 제외하기 위해 서블릿 컨테이너에 의해 호출되는 메서드이다.
이 메소드는 서블릿의 서비스 메소드 내의 모든 스레드가 종료되거나 제한 시간이 경과한 후에만 호출된다. 컨테이너가 이 메서드를 호출한 후에는 서블릿 컨테이너에서 해당 서블릿이 삭제되고 서비스 메서드를 다시 호출하지 못하게 된다.
위처럼 Servlet 인터페이스를 구현하기만 하면 서블릿이 등록되고 정상작동할까? 아니다. 서블릿 컨테이너(Servlet Container)
에 해당 서블릿을 등록해줘야 정상 작동이 가능하다.
즉, 서블릿은 Servlet Container(서블릿 컨테이너)
의 제어를 받는다고 볼 수 있다. 웹 서버에서 실행 중인 애플리케이션이 요청을 수신하면, 서버는 request를 서블릿 컨테이너
로 전달하고 Target Servlet(대상 서블릿, 요청 url과 HTTP 메서드 일치)
으로 전달한다.
스프링부트 프로젝트(정확히는 Spring MVC)를 진행하면, 서블릿을 관리해주는 코드를 개발자가 작성하지 않는다. 그럼에도 불구하고 요청과 응답을 컨트롤하기에 너무 쉽다. 그럼 요청과 응답을 처리하는 서블릿은 어디에 있고, 서블릿은 관리하는 서블릿 컨테이너는 어디에 있는걸까?
우선, 스프링부트에서 대표적인 서블릿은 디스패처 서블릿
이다. 디스패처 서블릿은 사용자로부터 들어온 요청을 받아 적절한 서블릿에 요청을 위임하는 역할을 가진 서블릿인데, 이것이 앞서 살펴본 서블릿 컨테이너
의 역할을 일부분 해준다고 볼 수 있다.
자세히 얘기하자면 스프링부트의 스프링 컨테이너(ApplicationContext)
내에서 디스패처 서블릿
이 관리되고, 디스패처 서블릿
은 요청과 처리를 위임할 빈(컨트롤러 혹은 서블릿)
을 찾아 요청과 처리를 담당해준다.
스프링 프로젝트에서 서블릿을 등록하는 방법은
@ServletComponentScan
어노테이션을 통해 프로젝트 내의 서블릿을 편하게 등록할 수 있다. 하지만 이 방법은 Servlet 도 빈으로 스프링 컨테이너에서 관리하는 방법이다.web.xml
파일로는 톰캣의 서블릿 컨테이너를 활용한다.
많이들 알고 있겠지만 스프링부트 프로젝트에서 HTTP 요청을 전달받아 처리하는 방법에는 여러가지가 있다.
web.xml
파일에서 직접 서블릿 등록 (Tomcat's Servlet Container)@WebServlet
어노테이션 + HttpServlet 클래스 상속 + @ServletComponentScan
(Spring Container, Bean)@Controller
or @RestController
어노테이션 (Spring Container, Bean)그렇기에 스프링 MVC 프레임워크에서는 컨트롤러 어노테이션을 활용하든 서블릿을 활용하든 잘 동작할 수 있도록, 요청url와 메서드에 맞는 적절한 서블릿 혹은 컨트롤러를 호출해주는 기능이 필요했다. 그 기능을 디스패처 서블릿
이 해주는 것이다. 이것을 프론트 컨트롤러로서의 역할이라고 한다.
단, 스프링부트 프로젝트에서 서블릿을 직접 등록하는 과정은 부가적인 코드 작성이 많아져 개발자들은 서블릿을 직접 등록하기 보다는 스프링 MVC 프레임워크의 @Controller
어노테이션을 활용하기 시작했다.
예전의 스프링 개발자들은 web.xml
파일로 서블릿을 등록해서 구현하는 경우가 많았다고 한다. 이 경우에는 스프링 컨테이너(ApplicationContext)
에서 빈으로 관리되는 것이 아니라, 내장 서버인 톰캣의 서블릿 컨테이너
에서 관리된다.
결론은 예전에는 서블릿을 직접 등록하는 스프링 개발자들이 많았다. 하지만, 최근에 들어서는 많은 개발자들이 @Controller 어노테이션
을 활용해 부가적인 코드 작성을 줄이고, 유지보수성과 코드 품질을 향상시키고 있다.
참고로,
@ServletComponentScan
어노테이션을 통해 서블릿을 등록하게 되면, 서블릿은스프링 컨테이너(ApplicationContext)
에서 관리된다.
Controller
는 MVC 라는 아키텍처 패턴에서 (Model-View-Controller) 에서 나온 개념이다. 스프링 MVC 프레임워크에서 @Controller
어노테이션을 만들어 개발자들이 직접 서블릿을 등록하지 않아도 서블릿의 역할을 해낼 수 있도록 구현해두었다.
서블릿
은 자바를 기반으로 하는 서버 측 웹 애플리케이션 개발을 위한 기술이다. 그리고 앞에서도 얘기했듯이 서블릿
은 HTTP 프로토콜에 종속적인 역할을 하는 인터페이스가 아니다. 용도에 따라서는 직접 구현하여 다양하게 사용될 수 있다. 다만 현재 거의 모든 인터넷이 HTTP 프로토콜을 기반으로 동작하기에 서블릿의 구현체인 HttpServlet
이 서블릿의 대표로 사용된다.
컨트롤러와 서블릿은 같은 역할을 한다고 봐도 무방하다. 다만 Spring MVC 프레임워크에서는 @Controller 어노테이션이 붙은 클래스를 서블릿으로 관리하는 것이 아니라, 스프링 컨테이너
에서 빈
으로 관리되며 해당 빈이 호출되어 요청을 처리하게 된다. 앞에서도 얘기했듯이 스프링MVC에서는 요청이 전달되는 과정에서 서블릿의 구현체인 디스패처 서블릿
이 사용된다.
컨트롤러와 별개로 Spring MVC 프레임워크 내에서도 서블릿을 직접 등록하여 서블릿을 사용할 수 있다.
찾아보고 생각을 정리하면서 쓰다보니 글이 두서없이 써진 것 같다..
하이튼! 컨트롤러와 서블릿의 역할은 비슷하다. 다만 차이점으로는 개념, 관리의 주체가 다르다는 점이 있다.
이전에는 톰캣의 서블릿 컨테이너 기능을 이용했다면 이제는 스프링 MVC 프레임워크에서는 서블릿 컨테이너의 역할을 스프링 컨테이너(ApplicationContext)
가 대신하며 코드의 품질과 유지보수성을 향상시켰다.
https://www.baeldung.com/java-servlets-containers-intro
https://www.baeldung.com/intro-to-servlets
https://www.baeldung.com/register-servlet
https://codeburst.io/understanding-java-servlet-architecture-b74f5ea64bf4
https://www.reddit.com/r/java/comments/kgwszh/is_controller_in_spring_mvc_a_servlet/
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet/context-hierarchy.html
https://docs.spring.io/spring-framework/docs/3.0.0.M4/spring-framework-reference/html/ch15s02.html
궁금했던 내용인데 잘 읽었습니다. 감사합니다!