스프링 컨테이너의 전체적인 순서는 다음과 같으며,
사용자가 요청하기 전에 서버가 켜져야 하는데 이 때 생기는 일들이다.
서버가 켜지고 톰켓이 실행되면 문지기 역할을 하는 web.xml이 호출되고, 자신이 해야하는 일들을 확인한다.
그 다음에 데이터베이스와 관련된 객체들(모든 스레드가 공유하는 자원)을 컴포넌트 스캔에서 메모리에 올린다.
*이 때 root-context 파일이 읽어진다.
이렇게 서버가 로딩이 되면 사용자에게 request 요청이 들어오게 되면서 디스패처 서블릿이 동작하게 되는데,
web.xml이 해야하는 역할을 자신이 대신해서 웹과 관련된 자원들을 메모리에 띄우고 주소 분배를 한다.
*이때는 servlet-context 파일이 읽어진다.
모든 요청이 끝나면 데이터로 응답할지, html 파일로 응답할지 결정한다.
아래에서 하나하나 살펴보며 정리해보자.
DispatcherServlet(디스패처 서블릿)에 의해 생성된 객체들은 어디에서 관리가 될까?
외부에서 request 요청이 오면, 스프링은 자바 파일을 요청하기 때문에 아파치가 동작할 수 없어 톰켓이 반응을 한다.
문지기와 같은 역할을 하는 web.xml은 스프링 내부로 들어가기 위해서 일을 하는데
이때 DispatcherServlet이 동작하며 컴포넌트를 스캔한다.
*DispatcherServlet = FrontController패턴과 RequestDispatcher의 결합이다.
궁극적인 목적은 어떤 주소가 들어왔을 때 어디로 가라고 주소를 분배해주는 것이다.
어딘가로 보내려면 클래스가 메모리에 떠있어야 보낼 수 있는데, 따라서 주소를 분배하기 전에 자신이 가지고 있는 자원들을 확인한다. (소스폴더 src안의 자바파일들)
이 자원들이 메모리에 뜨려면 new를 해야 한다.
static으로 만들어진 자바 파일 vs 일반 자바 파일
static은 메인메소드가 실행되기 전에 떠있는 자바 파일이다. 항상 메모리에 떠있다.
일반 자바 파일은 생성과 소멸이 일어나는 객체이며 특정한 타이밍에 메모리에 떴다가 사라진다.
우리가 만든 클래스들이 메모리에 떠있으려면 static으로 만들어줘야 한다. 스프링은 DispatcherServlet의 컴포넌트 스캔을 통해 src 내부의 모든 파일을 new해주는 역할을 한다. *스캔의 범위는 전체이다.
컴포넌트 스캔으로 필요한 파일들을 메모리에 올릴 때, 필요한 것은 어떻게 구분할까?
스프링이 정의한 어노테이션으로 필요한 파일들을 골라 올릴 수 있다.
ex. @Controller, @RestController , @Configration와 같은 어노테이션이 붙어있는 클래스는 메모리에 올리라고 명령을 내릴 수 있다.
메모리에 이렇게 클래스를 올리면 주소를 분배할 수 있고, 이렇게 컴포넌트를 스캔하고 메모리에 올려서 주소를 분배하는 것이 디스패처 서블릿의 역할이다.
서블릿이 만들어지면 스레드가 만들어지고, 요청한 사람들에 따라 사용하게 되며 각각의 스레드는 독립적으로 서로 영향을 받지 않는다.
ContextLoaderListener
DispatcherServlet에 의해 수많은 객체들이 만들어지기 전에 데이터베이스와 관련된 자원은 공통적으로 쓰이기 때문에 디스패처 서블릿으로 new할 필요 없이 미리 contextLoaderListener를 통해 띄운다.
이 때 읽는 것이 root-context.xml 파일이다. 이 파일은 스레드마다 공통적으로 쓰이는 것들을 메모리에 올리는 역할을 한다. 즉, 모든 스레드들이 공유해서 사용하는 것은 디스패처 서블릿으로 메모리에 올리기 이전에 root-context.xml파일로 띄우는 것이다.
IOC는 제어의 역전으로, 개발자가 new를 통해 객체를 생성하게 되면 변수 관리가 어렵기 때문에 스프링에 제어권을 넘겨서 스프링이 직접 객체를 관리하게 하고, 이 객체들은 보통 어노테이션을 붙여서 관리한다.
디스패처 서블릿이 컴포넌트를 스캔할 대 수많은 객체들이 applicationContext에 등록이 되고 이것이 IOC이다.
이렇게 띄워지는 주소는 필요할때 DI하면 되기 때문에 우리는 몰라도 상관이 없다. 필요한 곳에서 applicationContext에 접근해서 객체를 가져올 수 있으며 결국 applicationContext 안에 모든 객체의 정보가 담겨있게 된다.
applicationContext은 싱글톤으로 관리되기 때문에 어디에서 접근하든 동일한 객체라는 것을 보장해준다.
applicationContext
applicationContext에는 두 가지 종류가 있다.
- root-applicationContext
- servlet-applicationContext
root-applicationContext는 최상단의 컨텍스트로, 모든 것을 볼수가 있으며 데이터베이스와 관련된 일을 한다.
(모든 스레드가 공통적으로 공유하는 자원에 관한 것)
roo-applicationContext는 ContextLoaderListener에 의해 실행이 되고 이걸 실행하는건 web.xml이기 때문에 servlet-applicationContext보다 먼저 로드가 된다.
servlet-applicationContex는 서블릿만 보는 컨텍스트로, 웹과 관련된 일만 스캔해서 메모리에 올려준다.
bean factory(빈 팩토리)
필요한 객체를 bean factory에 등록할 수도 있다.
applicationContext와 다르게 초기에 메모리에 띄우지 않고 필요할 때 호출하기 때문에 lazy-loading이 가능하다.
요청 주소에 따른 적절한 컨트롤로 요청(Handler Mapping)
*Handler Mapping은 특정한 함수를 찾아준다.
사용자에게 요청이 들어오면 응답을 해야하는데, 이 때 html 파일로 응답할지, 데이터 파일로 응답할지 결정한다.
1)데이터 파일 응답
디스패처 서블릿이 컴포넌트 스캔을 통해 클래스를 메모리에 띄우면 주소분배를 위해 자신이 하는 것보다는 핸들러 매핑에게 역할을 떠넘기고, 핸들러 매핑은 적절한 함수를 찾아서 실행해준다. 스택이 실행될 때 메소드가 response(응답)되며 이렇게 메소드가 응답되는 것이 데이터 파일 응답이다 (데이터 리턴)
@ResponseBody 어노테이션을 붙이면 파일이 아닌 데이터로 보고 데이터로 응답할수 있으며 messageConverter가 응답하며 기본값 json으로 응답한다.
2)html 파일 응답
메소드가 아닌 html 파일로 응답하고 싶다면 ViewResolve로 파일 패턴을 만들어서 응답한다.
.jsp파일이라면 앞에는 경로가, 뒤에는 jsp확장자가 붙어서 해당 요청의 리턴값에 대한 파일의 패턴을 만들어주는 것이 ViewResolve의 역할이다.
정리하자면, 데이터로 응답할지 html 파일로 응답할지 결정하고,
html 파일로 응답하게 되면 ViewResolve가 관여하며,
데이터 파일로 응답하게 되면 message converter가 작동해서 json으로 응답하게 된다.
해당 게시글은 '최주호' 님의 스프링부트 개념정리 강의를 참고하였습니다.
'JAVA > Spring' 카테고리의 다른 글
프로젝트 만들기 (0) | 2022.02.17 |
---|---|
[스프링] 패키지 이름, UTF-8 (0) | 2022.02.17 |
스프링부트 JPA 개념잡기 (0) | 2022.01.08 |
web.xml과 FrontController 패턴 (0) | 2022.01.06 |
스프링부트의 동작 원리 (0) | 2022.01.06 |