-서블릿 (Servlet) 은 혼자서 실행되지 않으며, 반드시 서블릿 컨테이너(Servlet Container) 내에서 실행되어야 한다.
서블릿 컨테이너는 서블릿의 생명주기 관리, 요청 처리, 멀티스레드 관리, 보안 설정 등을 담당하며, 대표적으로 Tomcat, Jetty 같은 서버가 해당 역할을 수행한다.
<1> 웹 서버와의 통신 지원
서블릿은 혼자서 네트워크로부터 요청을 직접 받을 수 없다 --> 웹서버와 협력해야된다.
1. 사용자가 브라우저에 요청 : GET/ longin HTTP /1.1 2. 요청은 웹서버(ex. Tomcat)에 도착 3. 웹 서버는 이 요청을 서블릿컨테이너에게 넘김 4. 서블릿 컨테이너는 이 요청에 대응되는 서블릿을 찾아서 호출 5. 서블릿이 응답 데이터 생성 -> 서블릿 컨테이너가 웹서버로 전달 6. 웹서버가 사용자(브라우저)에게 응답 전송
<2> 서블릿 생명주기 관리
서블릿이 "언제 생성되고", "언제 초기화되고", "언제 제거되는지"를 자동으로 관리해줘야 안정적인 동작이 가능
[서버 시작] | 서블릿 클래스 로딩 | 서블랫 객체 생성 | init()호출 -> 초기설정 | [요청 발생 시] | service() / doGet() / doPost() 등 호출 | [서버 종료 시] | destory()호출 -> 자원정리
<3> 멀티스레드 지원 및 관리
웹 서버는 동시에 수많은 사용자의 요청을 처리해야 하니까 각 요청을 동시에 처리할 수 있어야 한다.
<작동방식> 1. 사용자가 여러 명 동시에 요청 2. 컨테이너는 요청당 스레드(Thread)를 하나씩 생성하거나 재사용 3. 이 스레드들이 하나의 서블릿 인스턴스를 공유하며 각각의 요청을 처리 4. 요청 처리 후 스레드는 풀에 반납
<스레드 풀??> 스레드를 매번 새로 만들지 않고 미리 만들어둔 스레드를 재사용 -> 성능 향상, 자원 절약
<주의점> 서블릿 인스턴스는 하나 -> 여러 스레드가 동시에 접근 -> 공유자원(ex. 인스턴스 변수)은 스레드 간 충돌 가능 -> synchronized등으로 동기화 필요
<서블릿 컨테이너 동작과정>
1. 클라이언트 요청
브라우저에서 HTTP 요청 전송
2. 요청/응답 객체 생성
컨테이너가 HttpServletRequest, HttpServletResponse 생성
3. 서블릿 매핑
URL에 따라 어떤 서블릿이 처리할지 결정
4. service() 호출
요청 타입에 따라 적절한 메서드 선택
5. doGet()/doPost() 처리
비즈니스 로직 수행, 응답 생성
6. 응답 전송
클라이언트에게 최종 결과 전송
서블릿 컨테이너가 모든 저수준 작업(요청 파싱, 응답 전송 등)을 처리해주기 때문에 → 개발자는 doGet()이나 doPost()에서 로직에만 집중할 수 있다.
스프링부트 안에도 서블릿이 숨어있음!!
-우리는 컨드롤러(@RestController)를 만들지만, 실제로는 이 컨트롤러들이 HTTP 요청/응답을 직접 처리하는게 아님
-요청/응답의 실제 입출구는? DispatcherServlet 이라는 서블릿(Servlet)이 처리!!
<Dispatcher Servlet이란?>
-스프링에서는 DispatcherServlet이 서블릿의 역할을 담당한다.
-클라이언트의 요청을 받아서 서블릿 컨테이너에서 관리되는 DispatcherServlet이 요청을 처리하고 반환하는 것이다.
<DispatcherServlet의 동작>
1. 클라이언트 요청 클라이언트에서 요청(HttpServletRequest)이 들어오면, 서블릿 컨테이너는 DispatcherServlet으로 이를 전달한다. 2. Handler 조회 DispatcherServlet은 핸들러 매핑(HandlerMapping)을 통해 요청 URI에 매핑된 핸들러(Controller)를 탐색한다. 3. Handler Adapter 조회 조회한 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다. 4. Handler Adapter 실행 핸들러 어댑터(HandlerAdapter)를 통해 핸들러(Controller)를 호출한다. 5. Handler(Controller) 실행 핸들러(Controller)를 실행하여 컨트롤러에서 요청을 처리하고, 응답을 다시 핸들러 어댑터로 반환한다. 6. ModelAndView 반환 핸들러 어댑터는 이 응답을 ModelAndView로 가공하여 반환한다. 7-1. @Controller 사용 시 1) View Resolver를 찾고 실행한다. 2) View Resolver는 View의 논리 이름을 물리 이름으로 바꾸고, 랜더링 역할을 담당하는 View 객체를 반환한다. 3) View를 랜더링 하여 클라이언트에 반환한다. 7-2. @RestController 사용 시 1) View와 ViewResolver를 거치지 않는다. 2) Controller로 부터 반환 받은 데이터를 MessageConverter를 거쳐서 Json 형식으로 변환한다. 3) Json을 ResponseBody로 응답한다.
1. 클라이언트 요청 사용자가 브라우저 또는 앱으로 HTTP 요청을 보냄 2. DispatcherServlet 진입 Spring Boot의 중앙 서블릿(Front Controller) 모든 요청은 DispatcherServlet으로 들어옴 3. 핸들러 매핑 (HandlerMapping) 이 요청을 어떤 컨트롤러 메서드가 처리할지 찾음 @GetMapping("/hello"), @PostMapping("/submit") 4. RestController 실행 찾은 컨트롤러 메서드를 실행함 5. MessageConverter 작동 컨트롤러가 리턴한 Java 객체(User 등)를 클라이언트가 이해할 수 있는 형태로 변환
Spring Boot에서 @RestController는 직접 응답을 만들지 않아도, Spring이 내부적으로 DispatcherServlet + HandlerMapping + MessageConverter 를 자동으로 사용해서 요청 → 실행 → JSON 응답까지 전부 처리해줍니다.