스프링 부트 동작원리

KOO HEESEUNG·2021년 6월 24일
4

Springboot with JPA

목록 보기
4/4
post-thumbnail

0. HTTP

소켓 통신은 계속 연결되어 있기 때문에 사용자가 늘어남에 따라 부하가 커진다. 그래서 HTTP 통신은 연결을 지속시키지 않고 끊어버리는 Stateless 방식을 사용한다. 연결이 끊기기 때문에 부하가 적지만, 이전에 보냈던 요청이나 되돌려준 응답에 대해서는 기억하지 못하는 단점이 있다. 이러한 단점을 보완하기 위해 만들어진 것이 웹서버이다.

1. 톰캣(Apache Tomcat)

1.1. 웹서버와 WAS의 차이

1.1.1. 정적 페이지와 동적 페이지
정적 페이지(Static Pages)동적 페이지(Dynamic Pages)
imgimg

정적 페이지란 서버에 미리 저장된 파일(HTML 파일, 이미지, JavaScript 파일 등)이 그대로 전달되는 웹 페이지를 말하며, 서버에 저장된 데이터가 수정되지 않는 한 항상 동일한 페이지를 반환한다.

반면, 동적 페이지는 서버에 있는 데이터들을 스크립트에 의해 가공처리한 후 생성되어 전달되는 웹 페이지를 말한다. 서버는 사용자의 요청을 해석하여 데이터를 가공한 후 생성된 웹 페이지를 반환하며, 사용자는 상황, 시간, 요청 등에 따라 달라지는 웹 페이지를 보게 된다.

1.1.2. 웹서버(Web Server)

웹서버는 HTTP 프로토콜을 기반으로 하여 클라이언트(웹 브라우저 또는 웹 크롤러)의 요청을 서비스하는 기능을 담당한다.

웹서버는 정적인 컨텐츠를 제공하고, WAS를 거치지 않고 바로 자원을 제공한다. 또한 동적인 컨텐츠 제공을 위해 클라이언트의 요청을 WAS로 보내고, WAS가 처리한 결과를 클라이언트에게 전달(응답)하는 역할을 한다.

웹서버의 종류로는 Apache, Nginx 등이 있다.

1.1.3. WAS(Web Application Server)

img

웹 페이지는 정적 컨텐츠와 동적 컨텐츠가 모두 존재한다. 사용자의 요청에 맞게 적절한 동적 컨텐츠를 만들어서 제공해야 하지만, 웹서버만을 이용한다면 사용자가 원하는 요청에 대한 결과값을 모두 미리 만들어놓아야 한다. 그러나 이렇게 하기에는 자원이 절대적으로 부족하기에 WAS를 통해 요청에 맞는 데이터를 DB에서 가져와서 그때 그때 결과를 만들어 제공함으로써 자원을 효율적으로 사용할 수 있다.

톰캣(Apache Tomcat)은 대표적인 WAS 중 하나로, JSP 페이지의 실행환경을 제공하는 웹 어플리케이션 서버이다. 톰캣은 자바코드를 이용해 HTML 페이지를 동적으로 생성한다. 웹 컨테이너(Web Container) 또는 서블릿 컨테이너(Servlet Container)라고도 한다.

1.1.4. 웹서버와 WAS를 분리하는 이유

WAS는 기본적으로 동적 컨텐츠를 제공하기 위해 존재하는 서버이다. DB 조회나 다양한 로직을 처리하느라 바쁜 WAS가 정적 컨텐츠 요청까지 WAS가 처리한다면, 그로 인한 부하가 더 커지게 되고, 수행 속도가 느려져 페이지 노출 시간이 늘어나게 될 것이다. 따라서 단순 정적 컨텐츠는 웹서버에서 빠르게 클라이언트에게 제공하도록 기능을 분리하는 것이 좋다.

즉, 자원 이용의 효율성 및 장애 극복, 배포 및 유지보수의 편의성을 위해 Web Server와 WAS를 분리한다.

✔︎ 참고

2. web.xml

web.xml은 웹 어플리케이션 배포시 어플리케이션의 환경을 설정하는 역할을 한다. 서버가 처음 로딩될 때 읽혀서 해당 환경설정을 Tomcat에 전달하며, web.xml의 내용은 다음과 같다.

2.1. ServletContext의 초기 파라미터 설정
2.2. Session의 유효시간 설정
2.3. Servlet/JSP의 정의 및 매핑
2.4. Error Pages 처리
2.5. 리스너/필터 설정
2.6. 보안

3. DispatcherServlet

3.1. FrontController 패턴

앞서 2에서 web.xml 내용에 Servlet/JSP 매핑이 있다고 서술했는데, 모든 클래스에 매핑을 적용시키기에는 코드가 너무 복잡해지기 때문에 FrontController 패턴을 사용한다.

최초 앞단에서 특정 주소로 요청(request)을 받으면 FrontController에 넘기고, FrontController에서는 그 주소에 맞는 자원을 찾아갈 수 있도록 다시 요청한다.

그런데 이 경우, 요청을 2번 하기 때문에 앞선 요청 정보가 사라지는 문제가 발생해 이를 유지시키는 방법이 필요하다. 그것이 바로 RequestDispatcher이다.

3.2. RequestDispatcher

RequestDispatcher는 필요한 클래스 요청이 도달했을 때 FrontController에 도착한 request와 response를 그대로 유지시켜준다.

3.3. DispatcherServlet

스프링에서는 FrontController 패턴을 직접 짜거나, RequestDispatcher를 직접 구현할 필요가 없다. DispatcherServlet이 있기 때문이다. DispatcherServlet은 FrontController 패턴 + RequestDispatcher 이다.

DispatcherServlet이 자동생성될 때, 수많은 객체가 생성(IoC)된다. 보통 필터들로, 기본적인 것들은 자동등록 되고, 사용자가 직접 등록할 수도 있다.

3.4. ApplicationContext

img

DispatcherServlet에 의해 생성되는 수많은 객체들은 ApplicationContext에서 관리된다. ApplicationContext에는 servlet-applicationContext와 root-applicationContext 두가지가 있다.

클라이언트로부터 처음 요청이 들어오면 DispatcherServlet이 동작한다. DispatcherServlet은 주소를 분배하는 역할을 한다. 주소를 분배하기 위해서는 메모리에 그에 맞는 자원이 올라가 있어야 한다. 그래서 DispatcherServlet은 컴포넌트 스캔을 통해 특정 폴더 내의 자원들을 스캔하여 필요한 것들을 메모리에 올린다(IoC). 필요한 것들인지 여부는 어노테이션을 붙여 판단할 수 있도록 한다.(ex> @Controller, @Configuration, @Repository, @Service 등....)

3.4.1. servlet-applicationContext

servlet-applicationContext는 ViewResolver, Interceptor, MultipartResolver 객체를 생성하고, 웹과 관련된 어노테이션 @Controller, @RestController를 스캔한다. 해당 파일은 DispatcherServlet에 의해 실행된다.

3.4.2. root-applicationContext

root-applicationContext는 어노테이션 @Service, @Repository 등을 스캔하고, DB 관련 객체를 생성한다. 해당 파일은 ContextLoaderListener에 의해 실행된다.

ContextLoaderListener를 실행해주는 녀석은 web.xml이기 때문에 root-applicationContext는 servlet-applicationContext보다 먼저 로드된다. 때문에 servlet-applicationContext에서는 root-applicationContext가 로드한 객체를 참조할 수 있지만, 그 반대는 불가능하다.

img

✔︎ 참고

0개의 댓글