다크 모드에서 그림이 잘 보이지 않습니다. 라이트 모드에서 읽는 것을 추천합니다.
오늘의 목표는 스프링이 요청을 처리하는 내부적인 원리 이전에 서버가 클라이언트의 요청을 어떻게 처리하는지에 대한 큰 틀을 이해하는 것이다.
Tomcat(WAS)
Tomcat은 WAS(Web Application Server)의 대표적인 미들웨어 서비스이다.
WAS
는 웹 서버와 웹 컨테이너의 결합으로 다양한 기능을 컨테이너에 구현하여 다양한 역할을 수행할 수 있는 서버를 말한다.
클라이언트의 요청이 있을 때 내부의 프로그램을 통해 결과를 만들어내고 이것을 다시 클라이언트에 전달해주는 역할을 하는 것이 바로 웹 컨테이너이다.
Flow
Web server
웹 서버는 사용자가 웹 브라우저에서 URL 입력했을 때 사용자에게 응답을 처리하는 http 통신의 일련의 과정을 진행한다.
이 통신을 위해 소켓 연결 등의 네트워크 처리를 해주며 html, css, js 등의 정적 소스에 대한 요청에 대해 응답한다.
정적 소스를 별도로 처리하는 이유는 동적 컨텐츠를 처리하는 WAS에 부담을 줄 필요는 없기 때문에 WAS와 업무를 나누어 처리하여 각 서비스의 목적에 따른 성능상의 장점을 살리기 위함이다.
또한, 웹서버는 클라이언트와의 연결을 WAS로 전달하여 WAS가 클라이언트와 직접 통신하지 못하도록 중계 역할을 해주어
WAS에게 클라이언트와의 연결에 대한 독립성을 보장해주며, 보안적으로도 한 단계 안전 할 수 있도록 해준다
Apache tomcat 5.5 이후 부터 Web server의 기능인 httpd(웹서비스 데몬) native 모듈을 가지고와서 정적파일을 처리하기 때문에 별도의 Web server 기능에 뒤쳐지지 않는 정적파일 처리할 수 있다.
Servlet
Servlet Container를 보기 전에 서블릿(Servlet)에 대해서 알아보자.
일반적으로 웹 프로그래밍을 한다고 하면 정의된 클라이언트의 요청에 대해 상응하는 결과를 return해 주어야 하는데,
웹 페이지 혹은 결과 값을 동적으로 생성해주기 위한 역할을 하는 자바 프로그램을 서블릿이라고 한다.
다음은 java8에서 제공하는 Servlet 인터페이스이다.
javax.servlet.Servlet.java
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
위의 인터페이스를 보면 서블릿의 life cycle(init
> service
> destroy
)을 볼 수 있다.
옛날 CGI(Common Gateway Interface)를 Java로 구현하기 위해 서블릿을 직접 다뤘다고 한다.
javaEE로 웹서비스를 직접 구현할 때 서블릿을 만들기 위해 위의 Servlet 인터페이스의 구현체를 직접 만들어 사용했지만, spring에서는 Dispatcher Servlet
이라는 모든 요청을 담당하는 서블릿을 두고 컨트롤러에 위임을 하여 요청을 처리한다.
Dispatcher Servlet
다음은 Spring framework에 구현되어 있는 DispatcherServlet.java 이다.
package org.springframework.web.servlet;
@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet {
public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
this.detectAllHandlerMappings = detectAllHandlerMappings;
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context); // point 1
initHandlerAdapters(context); // point 2
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context); // point 3
initFlashMapManager(context);
}
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// omitted...
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// omitted...
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// omitted...
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
// omitted...
}
Spring에서 제공해 주고 있는 Dispatcher Servlet은 [FrameworkServlet.java <- HttpServlet.java <- Servlet.java] 를 상속받아 구현한 서블릿이다.
Dispatcher Servlet은 클래스 내부에 Handler, Adapter, Resolver 등을 가지고 클라이언트의 요청에 따라
개발자가 정의해둔 내용을 응답해주는 중추의 역할로 front controller
라고 부르기도 한다.
- HandlerMapping
Client로부터 들어온 Request를 분석하여 매핑된 Controller가 있는지 확인한다.
- HandlerAdapter
매핑 대상 Controller에게 Request 처리 요청을 보낸다.
- ViewResolver
Controller에서 view를 return 했을 경우 해당하는 view를 찾아 client에게 return한다.
Servlet container
탐캣의 메인 기능인 서블릿 컨테이너(Servlet container)의 역할은 다음과 같다.
- 서블릿 관리
위의 서블릿 라이프사이클( init > service > destroy)의 흐름대로, 서블릿 클래스의 로드, 초기화, 호출, 소멸까지의 라이프사이클을 직접적으로 관리한다.
서블릿으로 구현된 Dispatcher Servlet 역시 서블릿 컨테이너에서 수행된다.
- 통신을 위한 연결 생성
서블릿 컨테이너는 웹서버와 통신을 통해 클라이언트의 request를 전달받아 동적 서비스를 response를 응답하기 위해 통신을 위한 소켓을 만드는 등의 역할을 한다.
- Thread Pool 관리
- 클라이언트로부터 request를 받을때마다 스레드를 생성해 요청을 처리하는데, 해당 스레드는 서블릿 컨테이너에서 쓰레드풀을 별도로 관리하여 실행한다.
Spring container (IoC container)
DispatcherServlet 내부에 Servlet WebApplicationContext
와 Root WebApplicationContext
가 동작하는 것으로 보이지만, 이 두 ApplicationContext는 스프링 컨테이너에서 동작하는 컨텍스트라고 보면 된다.
서블릿 컨테이너는 서블릿의 생명주기를 관리했다면, 스프링 컨테이너는 Java object인 빈(Bean)의 라이프 사이클 관리하여 Spring 프레임워크의 특징인 IOC(제어역전)와 DI(의존성주입)을 제공해주는 역할을 한다.
정리
- Server 구동 단계
- Web server init
- Root WebApplicationContext 로딩
- Web server start
- Client와의 상호 작용 단계
- Client -> Web Server로 request
- 동적 Web server -> Servlet Container로 전달
- Servlet Container Thread 생성
- DispatcherServlet init() (서블릿 생성 안되어 있을 경우)
- 생성된 쓰레드에서 DispatcherServlet service() 메서드 호출
- HandlerMapping을 통해 매핑 컨트롤러 조회
- HandlerAdapter를 통해 매핑 컨트롤러에 request 전달
- 개발자가 구현한 Controller -> Service -> Repository 동작
Reference
Tomcat, Spring MVC의 동작 과정
(부제 : 스프링 웹 프로그래밍을 하는 당신, 클라이언트의 요청을 어떻게 처리하는지 알고 있는가?) Tomcat 일반적으로 탐캣(Tomcat)은 ‘WAS(Web Application Server)’의 대표적인 미들웨어 서비스로 알려
taes-k.github.io
Spring Framework Documentation
Overview history, design philosophy, feedback, getting started. Core IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP. Testing Mock Objects, TestContext Framework, Spring MVC Test, WebTestClient. Data Access Tran
docs.spring.io
틀린 점이나 개선할 점은 지적해주세요. 저에게 큰 도움이 됩니다 :)
'Spring' 카테고리의 다른 글
JPA 사용해보기 (0) | 2022.11.15 |
---|---|
Unit test naming convention (0) | 2022.11.15 |
RequestParam으로 List 형식 받기 (0) | 2022.07.07 |
@Primary, @Qualifier (0) | 2022.04.29 |
스프링 프레임워크 핵심 기술 - IoC 컨테이너와 Bean (0) | 2022.04.28 |