웹서버(아파치)는 자바코드를 읽을 수 없기 때문에 jsp와 같은 파일을 웹브라우저의 요청에 대해서 응답해줄 수가 없다.
이를 해결하기 위해 톰켓이 존재한다.
톰켓은 jsp파일의 자바코드를 컴파일 하여 html파일로 변환한다. 그리고 웹서버에 다시 전달하면 웹서버가 웹브라우저에 응답해주게 된다.
서블릿 컨테이너
웹브라우저에서 URL(자원 접근)을 통해 정적인 파일을 요청할 때는 웹서버가 작동한다.
웹브라우저에서 URI(식별자 접근)을 통해 자바 파일을 요청할 때는 톰켓이 작동한다.
스프링의 경우에는 URL 접근 방식이 불가능하다. 특정 파일만 요청하는 게 불가능하다는 말이며, 톰켓과 자바를 무조건 거쳐야 한다는 뜻이다.
클라이언트로부터 어떠한 요청이 왔을 때, 서블릿 컨테이너는 최초요청일 경우에는 스레드를 하나 생성하고 응답을 해준다. 기본적으로 멀티스레드 이기 때문에 동시에 여러 처리를 해줄 수 있지만, 보유하고 있는 스레드가 모두 작동 중일 경우에는 딜레이 후에 동작이 완료된 스레드에 배정되어 응답하게 된다.
web.xml
ServletContext의 초기 파라미터
Session의 유효시간 설정
Servlet/JSP에 대한 정의
Servlet/JSP 매핑
Mime Type 매핑
Welcome File list
Error Pages 처리
리스너/필터 설정
보안
여기에서 Servlet/JSP 매핑시(web.xml에 직접 매핑 or @WebServlet 어노테이션 사용)에 모든 클래스에 매핑을 적용시키기에는 코드가 너무 복잡해지기 때문에 FrontController 패턴을 이용함.
FrontController 패턴
최초 앞단에서 request 요청을 받아서 필요한 클래스에 넘겨준다. 왜? web.xml에 다 정의하기가 너무 힘듬.
이때 새로운 요청이 생기기 때문에 request와 response가 새롭게 new될 수 있다. 그래서 아래의 RequestDispatcher가 필요하다.
RequestDispatcher
필요한 클래스 요청이 도달했을 때 FrontController에 도착한 request와 response를 그대로 유지시켜준다.
DispatcherServlet
FrontController 패턴을 직접짜거나 RequestDispatcher를 직접구현할 필요가 없다. 왜냐하면 스프링에는 DispatcherServlet이 있기 때문이다. DispatcherServlet은 FrontController 패턴 + RequestDispatcher이다.
DispatcherServlet이 자동생성되어 질 때 수 많은 객체가 생성(IoC)된다. 보통 필터들이다. 해당 필터들은 내가 직접 등록할 수 도 있고 기본적으로 필요한 필터들은 자동 등록 되어진다.
스프링 컨테이너
DispatcherServlet에 의해 생성되어지는 수 많은 객체들은 ApplicationContext에서 관리된다. 이것을 IoC라고 한다.
ApplicationContext
IoC란 제어의 역전을 의미한다. 개발자가 직접 new를 통해 객체를 생성하게 된다면 해당 객체를 가르키는 레퍼런스 변수를 관리하기 어렵다. 그래서 스프링이 직접 해당 객체를 관리한다. 이때 우리는 주소를 몰라도 된다. 왜냐하면 필요할 때 DI하면 되기 때문이다.
DI를 의존성 주입이라고 한다. 필요한 곳에서 ApplicationContext에 접근하여 필요한 객체를 가져올 수 있다. ApplicationContext는 싱글톤으로 관리되기 때문에 어디에서 접근하든 동일한 객체라는 것을 보장해준다.
ApplicationContext의 종류에는 두가지가 있는데 (root-applicationContext와 servlet-applicationContext) 이다.
a. servlet-applicationContext
servlet-applicationContext는 ViewResolver, Interceptor, MultipartResolver 객체를 생성하고 웹과 관련된 어노테이션 Controller, RestController를 스캔 한다. 해당 파일은 DispatcherServlet에 의해 실행된다.
b. root-applicationContext
root-applicationContext는 해당 어노테이션을 제외한 어노테이션 Service, Repository등을 스캔하고 DB관련 객체를 생성한다. (스캔이란 : 메모리에 로딩한다는 뜻) 해당 파일은 ContextLoaderListener에 의해 실행된다. ContextLoaderListener를 실행해주는 녀석은 web.xml이기 때문에 root-applicationContext는 servlet-applicationContext보다 먼저 로드 된다.
당연히 servlet-applicationContext에서는 root-applicationContext가 로드한 객체를 참조할 수 있지만 그 반대는 불가능하다. 생성 시점이 다르기 때문이다.
Bean Factory
필요한 객체를 Bean Factory에 등록할 수 도 있다. 여기에 등록하면 초기에 메모리에 로드되지 않고 필요할 때 getBean()이라는 메소드를 통하여 호출하여 메모리에 로드할 수 있다. 이것 또한 IoC이다. 그리고 필요할 때 DI하여 사용할 수 있다. ApplicationContext와 다른 점은 Bean Factory에 로드되는 객체들은 미리 로드되지 않고 필요할 때 호출하여 로드하기 때문에 lazy-loading이 된다는 점이다.