1. 웹 애플리케이션의 기본 구조 이해하기
1.1 Web Server와 WAS의 구분
Web Server
Apache
, Nginx와 같은 서버- HTML, CSS, JavaScript 등
정적 파일 제공
- 간단한 요청-응답 처리
- 빠른 처리 속도가 장점
WAS
Web Server
+web Container
- Tomcat, JBoss와 같은 서버
- 비즈니스 로직 처리
- 데이터베이스 연동
동적 컨텐츠 제공
1.2 Web Server와 Web Container가 같이 있을 경우
- WAS는 웹 서버의 기능을 포함하기 때문에 웹 서버의 기능을 제공할 수 있다.
- WAS와 DB만으로도 시스템 구성이 가능하지만, WAS가 너무 많은 기능을 담당해 서버 과부하의 우려가 생긴다.
- 정적 컨텐츠의 요청까지 WAS가 처리한다면 정적 데이터 처리로 인해 서버에 부하가 커지게 되고, 동적 컨턴츠의 처리가 지연됨에 따라 서비스의 속도가 느려질 수 있다.
- WAS 장애시 오류화면 노출이 불가능해진다.
1.3 Web Server와 Web Container와 분리하는 이유
- 기능을 분리하여 서버 부하 방지
- WAS가 웹 서버의 기능을 포함해 모든 역할을 혼자 수행할 수 있지만 그만큼 WAS가 감당해야하는 작업이 많아지게 된다. 그렇기 때문에 각 서버가 감당하는 작업을 줄여 보다 효율적인 사용이 가능하도록 하기 위해 웹 서버와 WAS를 분리한다.
- 물리적으로 분리하여 보안 강화
- WAS에는 웹 어플리케이션이 올라가있기 때문에 외부와 직접 연결되어 있다면 중요한 설정이나 파일들이 외부로 노출될 위험이 있다. 웹 서버를 WAS 앞에 위치시켜 리소스를 보다 안전하게 보호할 수 있다.
- 웹 서버에 여러대의 WAS를 연결 할 수 있다.
- Load Balancing(서버나 컴퓨터에 가해지는 부하를 분산해주는 기술)을 위해서 Web Server를 사용한다.
- fail over(작동 중지된 WAS 대신 다른 WAS를 사용해 장애 극복)에 유용
- fail back(작동 중지된 WAS를 재작동 시킴)에 유용
- 특히 대용량 웹 어플리케이션의 경우(여러개의 서버 사용) Web Server와 WAS를 분리하여 무중단 운영을 위한 장애 극복에 쉽게 대응할 수 있다.
- 예를 들어, 앞 단의 Web Server에서 오류 발생시 WAS를 이용하지 못하도록 한 후 WAS를 재시작함으로써 사용자는 오류를 느끼지 못하고 이용할 수 있다.
- 여러 웹 어플리케이션 서비스 가능
- 예를 들어, 하나의 서버에서 PHP Application과 Java Application을 하나의 웹 서버에 연결해 함께 사용할 수 있다.
1.4 Web Service Architecture
웹 시스템은 다양한 구조로 설계가 가능하다.
Client - Web Server - DB
Clinet - WAS - DB
Client - Web Server - WAS - DB
이중에서 Client - Web Server - WAS - DB
의 웹 시스템 구성이 가장 효율적으로 리소스를 관리할 수 있는 구성이다.
Web Server를 WAS앞에 두고 정적 콘텐츠를 Web Server가 처리하고 동적 콘텐츠는 WAS에게 요청을 위임함으로써 WAS는 중요한 애플리케이션 로직 처리를 전담할 수 있게 된다.
1.5 전통적인 Client - Web Server - WAS - DB 웹 시스템 구조의 요청 처리 순서
- Web Server는 클라이언트로부터
HTTP 요청
을 받는다. - Web Server는 클라이언트의 요청을 WAS에 보낸다.
- WAS는 관련된 Servlet을 메모리에 올린다.
- WAS는
web.xml
을 참조하여 해당 Servlet에 대한 Thread를 생성한다. (Thread Pool 이용) HttpServletRequest
와HttpServletResponse
객체를 생성하여 Servlet에 전달한다.- Thread는 Servlet의
service()
를 호출한다. service()
는 요청에 맞게doGet()
또는doPost()
메서드를 호출한다.
- Thread는 Servlet의
doGet()
,doPost()
메서드는 인자에 맞게 생성된 적절한 동적 페이지를Response
객체에 담아서 WAS에 전달한다.- WAS는
Response
객체를HttpResponse
형태로 바꾸어 Web Server에 전달한다. - 생성된 Thread를 종료하고,
HttpServletRequest
와HttpServletResponse
객체를 제거한다.
2. Servlet Container
2.1 Servlet
서블릿(Servlet)은 클라이언트의 요청을 처리하고, 그 결과를 다시 클라이언트에게 전송합니다. Servlet을 통해 웹 페이지를 동적으로 생성하여 클라이언트에게 반환해 줄 수 있습니다.
Servlet 인스턴스는 싱글톤으로 생성되며, Thread-Safe 하지 않기 때문에 무상태 혹은 읽기 전용 상태, 동기화 처리된 구조로 설계되어야 합니다. 이러한 특성을 가지는 Servlet 을 Servlet Container
가 멀티 쓰레딩 기능을 통해 관리합니다
2.2 전통적인 Servlet Container가 하는 일
서버에 만들어진 서블릿이 스스로 작동하는 것이 아니라, 서블릿을 관리 해주는 것이 필요한데, 이러한 역할을 하는 것이 바로 서블릿 컨테이너 입니다.
즉, 서블릿
을 요구사항 명세서
라고 표현한다면, 서블릿 컨테이너
는 그 명세서를 보고 개발하는 개발자
입니다.
- 웹 서버와 통신 지원이를
Servlet Container
가 알아서 해주기 때문에 개발자는 통신 기능에 대해서 신경 쓰지 않고 - 클라이언트의 요청에 대한 비즈니스 로직에만 집중할 수 있습니다
Servlet Container
는Servlet
과Web Server
가 통신할 수 있도록 해줍니다.- Servlet 생명주기 관리요청이 들어오면 관련된
Servlet
을 찾고 없다면 초기화합니다.Servlet
의 역할이 끝난후 GC 를 진행하여 관련된 인스턴스를 소멸시킵니다. - 또한
Servlet
의 service() 메소드를 호출해서 실제 기능을 하도록 합니다. Servlet
의 생성과 호출 소멸을 관리합니다.- 멀티 쓰레딩 관리
Servlet Container
는 요청이 들어올 때마다 새로운 자바 쓰레드를 생성하여 멀티 쓰레딩 방식으로 처리합니다. - 여기서 쓰레드는 무한적으로 생성할 수 있는것은 아닙니다.
Servlet Container
내부에는 쓰레드 풀을 가지고 있으며 기본 값으로 200개의 쓰레드(톰캣 기준)가 존재합니다.요청이 들어오면 쓰레드 풀에서 쓰레드를 하나 가져옵니다 ❗️(컨트롤러는 Thread-Safe 함) - 앞에서 언급했던 것처럼
Servlet Container
가 관리하는Servlet
은 싱글톤 패턴으로 관리됩니다. 그렇다면 동시에 같은Servlet
로 여러 요청이 들어올 때 어떻게 처리할 수 있을까요? - JSP 지원JSP(Java Server Page) 를 Servlet 으로 변환시켜 처리합니다.
2.3 전통적인 Servlet 생명주기 관리
- 클라이언트 요청이 들어오면
Servlet Container
는Servlet
이 힙 영역에 있는지 확인합니다.만약 존재하지 않는다면 init() 메소드를 호출하여 적재합니다. - 클라이언트 요청에 따라서 service() 메소드를 통해 요청에 대한 응답이 생성됩니다.
Servlet Container
가Servlet
종료 요청을 하면 destory() 메소드가 호출됩니다.종료시 처리해야 하는 작업은 destory() 메소드를 오버라이딩하여 구현하면 됩니다. 종료된Servlet
인스턴스는 CG 에 의해 메모리에서 제거됩니다.
서블릿 컨테이너는 서블릿의 생명주기를 다음과 같이 관리합니다:
- 초기화 단계 (init)
- 서블릿 인스턴스 생성
- 필요한 리소스 할당
- 한 번만 실행
- 서비스 단계 (service)
- 클라이언트 요청 처리
- doGet(), doPost() 등 메서드 호출
- 여러 번 실행 가능
- 소멸 단계 (destroy)
- 리소스 해제
- 서블릿 종료
- 한 번만 실행
2.5 Spring의 Servlet Container
스프링 MVC와 DispatcherServlet
스프링 MVC의 DispatcherServlet은 일반적인 서블릿과는 다음과 같은 차이가 있습니다:
- DispatcherServlet은 싱글톤으로 유지:
스프링 컨텍스트
가 초기화될 때, DispatcherServlet도 함께 생성되고 애플리케이션이 종료될 때까지 싱글톤으로 유지됩니다.- 요청이 끝났다고 해서 DispatcherServlet이 소멸되거나 GC의 대상이 되지 않습니다. 계속 메모리에 남아 있으며, 모든 HTTP 요청을 처리하는 중심 역할을 수행합니다.
- 서블릿 생명주기와 스프링 관리:
- Servlet의 생성, 초기화, 요청 처리, 소멸 등은 서블릿 컨테이너가 관리하지만, DispatcherServlet 내부에서 비즈니스 로직이나 컨트롤러, 서비스 등의 라이프사이클은 스프링 컨테이너(Application Context)가 관리합니다.
- 서블릿 객체 자체의 생성과 소멸은 서블릿 컨테이너의 책임이지만, 그 내부 동작은 스프링이 주도합니다.
- 일반 서블릿: 요청이 들어올 때마다 서블릿이 동적으로 생성되고, 요청이 끝나면 소멸되거나 GC 대상이 됩니다.
- DispatcherServlet: 한 번 생성된 후 애플리케이션 종료 시까지 싱글톤으로 유지되며, 메모리에 상주하면서 모든 요청을 처리합니다.
3. Spring Container
위 Servlet Container는 서블릿들을 초기화할 때,
Spring Container는 각각의 서블릿이 제대로 동작하기 위해 필요한 의존성 주입(DI)을 제공한다.
두 컨테이너는 이렇게 밀접한 관계에 있기 때문에 Spring Container에 짚고 넘어갈 필요가 있다.
Spring Container의 역할은 빈(Bean) 객체들을 생성하고,
빈 객체들 간의 의존성을 관리하며 빈 객체들을 필요한 곳에서 주입(Injection)해주는 등의 역할을 맡는다.
빈 객체를 생성하고 생명주기를 관리할 때 스프링 컨테이너가 직접 컨트롤 하기 때문에
Inversion of Control (IoC) 방식이라고 불리며
객체 생성, 관리, 의존성 관련 코드들이 아닌, 서비스에 대한 코드에만 집중할 수 있는 장점이 있다.
때문에 Spring Container는 IoC Container라고도 불린다.
스프링 부트 어플리케이션을 실행하면, SpringApplication.run(....) 메서드가 알아서 어플리케이션 컨텍스트를 생성하고 초기화한다. 이 과정에서 어노테이션 기반의 설정 정보가 사용되므로 내부적으로는AnnotationConfigApplicationContext와 같은 클래스가 사용되지만, 개발자가 직접 이 클래스를 사용하는 것은 아니다. (즉, 스프링부트가 알아서 이 클래스를 사용해 빈을 등록하고 초기화하고 삭제한다.)
3.1 Spring Container의 종류
BeanFactory
, ApplicationContext
크게 2가지로 나눌수 있다.
BeanFactory
BeanFactory
는 빈을 등록하고 생성하고 조회하고 돌려주는 등 빈을 관리하는 역할을 한다.
getBean() 메소드를 통해 Bean을 인스턴스화 할 수 있으며 그 외에 부가적인 빈을 관리하는 기능을 담당한다.
즉 스프링컨테이너의 가장 기본적이며 핵심적인 기능을 담고있다.
getBean()이 호출되면 BeanFactory
는 의존성 주입을 통해 빈을 인스턴스화하고, 빈의 특성을 설정하기 시작하며 여기서 빈의 라이프사이클이 시작된다.
ApplicationContext
스프링이 제공하는 각종 부가 서비스를 추가로 제공하며 BeanFactory
를 상속한 인터페이스이다. 이 인터페이스를 구현하는 여러 컨테이너가 있으며
BeanFactory
와 다른 점은 BeanFactory
는 getBean() 메소드가 호출된 시점에서 지연로딩(LAZY)을 시작하여 생성해주지만 ApplicationContext
초기화 시점에 모든 빈을 미리 로드한 후(EAGER) 필요할때 빈을 지연 없이 얻을 수 있다.
ApplicationContext
을 구현하는 컨테이너는 크게
FileSystemXmlApplicationContext
, AnnotationConfigApplicationContext
또는
ClassPathXmlApplicationContext
등이 있다.
3.2 ApplicationContext의 구현체 3가지
ClassPathXmlApplicationContext 와 FileSystemXmlApplicationContext
xml 파일로 빈객체들의 생성과 의존관계를 정의하면 이 xml 파일을 이용하여 빈 객체를 생성하고 관리한다. 스프링 프레임워크 초기부터 사용된 가장 간단한 형태의 스프링 컨테이너라고 할 수 있다.
두 컨테이너의 가장 큰 차이점은 xml 파일의 경로이여
ClassPathXmlApplicationContext
는 리소스 폴더(src/main/resources/...)에서,
FileSystemXmlApplicationContext
는 보통 프로젝트 외부 경로의 xml 파일을 사용할 때 사용된다.
xml 파일 기반으로 빈객체들을 관리하기 때문에 다음과 같은 단점이 있다.
- xml 파일의 내용이 바뀌면 다시 빌드/배포해야하는 번거로움이 있다.
- 규모가 커진다면 xml 파일 내용이 길어지고 가독성이 떨어진다.
- 빈객체들을 런타임때 메모리에 로드되므로 (LAZY로딩) 자원소모가 큰 경우 적절하지 못하다.
- 동적으로 빈객체들의 구성이 변경되어야한다면 사용할 수 없다.
이와 같은 단점을 가지고 있지만 비교적 쉽게 사용할 수 있기 때문에 간단한 작은 규모의 테스트 프로젝트 등에서 종종 사용된다.
AnnotationConfigApplicationContext
가장 자주 사용되는 스프링 컨테이너이며 xml 파일을 사용하는 대신 자바 어노테이션으로 구성된 설정 클래스를 사용한다.
이 설정 클래스를 생성하고, 이를 바탕으로 스프링 빈을 생성한다.
@Component, @Service, @Repository, @Controller 등으로 자동으로 빈객체를 구성할 수 있고
@Autowired, @Qualifier, @Value 등의 어노테이션을 사용하여 빈객체 간의 의존성을 관리할 수 있다.
자바 코드로 작성되기 때문에 컴파일 단계에서 에러를 검출할 수 있다.
3.3 WebApplicationContext
Spring Web 관련 디펜던시를 추가하면 일반적으로 WebApplicationContext
가 사용됩니다.
WebApplicationContext
는 스프링 웹 애플리케이션에서 사용하는 ApplicationContext
의 특별한 구현체입니다. 이 컨텍스트는 스프링 MVC 애플리케이션에서 사용되며, 웹 관련 빈을 관리합니다. WebApplicationContext
는 ApplicationContext
를 상속하고 있으며, 웹 애플리케이션의 설정과 관련된 여러 기능을 제공합니다.
- DispatcherServlet과 통합: 스프링 웹 애플리케이션에서는
DispatcherServlet
이WebApplicationContext
를 사용하여 요청을 처리합니다.DispatcherServlet
은 이 컨텍스트를 통해 웹 애플리케이션의 컨트롤러, 서비스, 리포지토리 등을 관리하고 요청을 처리하는 로직을 수행합니다. - 루트 컨텍스트 초기화:
ContextLoaderListener
는WebApplicationContext
를 초기화하고 관리합니다. 이 컨텍스트는 애플리케이션의 비즈니스 로직과 관련된 빈을 관리하며, 웹 애플리케이션에서 필요한 공통된 빈들을 제공합니다. 예를 들어, 데이터베이스 연결을 위한 서비스나 리포지토리 빈이 포함됩니다.
3.4 ApplicationContext와 WebApplicationContext 관계
그림에서 보여지는 것처럼 WebApplicationContext
와 ApplicationContext
는 선택해서 사용하는 것이 아니라 보통 함께 사용됩니다. 두 가지 컨텍스트는 다르게 동작하지만 서로 연관되어 있습니다.
WebApplicationContext
는 웹 애플리케이션에서 필요한 DispatcherServlet
과 관련된 빈들을 관리합니다. 이 컨텍스트는 주로 웹 관련 컴포넌트인 컨트롤러, 뷰 리졸버, 핸들러 매핑 등을 포함합니다. 웹 애플리케이션에서 DispatcherServlet
이 요청을 처리할 때 WebApplicationContext
가 사용됩니다.
반면에 ApplicationContext
는 스프링 애플리케이션의 전반적인 설정과 빈들을 관리하는 상위 컨텍스트입니다. WebApplicationContext
는 이 ApplicationContext
의 하위 컨텍스트로서, 보다 넓은 범위에서의 설정을 관리합니다. ApplicationContext
는 일반적으로 서비스, 데이터베이스 연결 등의 비즈니스 로직과 관련된 빈들을 관리합니다.
참고
https://sigridjin.medium.com/servletcontainer와-springcontainer는-무엇이-다른가-626d27a80fe5
'스프링 > 기본지식' 카테고리의 다른 글
@Transactional 어노테이션에 대한 작동방식 (0) | 2024.12.16 |
---|---|
OSIV (0) | 2024.12.10 |