2-Layered Architecture
2-Layered Architecture
일반적으로 프레임워크 기반의 웹 프로젝트에서 사용하는 방식으로 아래와 같이 두 개의 레이어로 나누어서 시스템을 개발하는 방식을 의미합니다.
- 기본적인 스프링 MVC 프로젝트 생성 시 2가지 Layer 기준으로 xml 설정 파일도 두가지로 나눕니다.
1) Presentation-layer.xml (Presentation Layer) : /WEB-INF/ 하위 경로에 위치
(기본 파일명: servlet-context.xml)
2) Application-layer.xml (Business Layer) : /WEB-INF/ 하위 경로에 위치
(기본 파일명 : root-context.xml)
- 기본적으로 위의 사진과 같이 웹을 로딩하면 Presentation Layer의 DispatcherServlet이 생성됩니다. 이때 Presentation-layer.xml 파일을 읽어서 스프링 컨테이너를 구동하면 Contreller 객체들이 메모리에 생성됩니다.
하지만 Controller 객체들이 생성되기 전에 먼저 src/main/resources 폴더의 ApplicationContext.xml 파일을 읽어서 비지니스 컴포넌트를 메모리에 생성해야 하고 이때 사용되는 클래스가 스프링에서 제공하는 ContextLoaderListener 입니다.
* Spring MVC 프로젝트 생성 시 기본 web.xml
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- applicationContext.xml 에 해당하는 경로 -->
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- presentation-layer.xml에 해당하는 경로 -->
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 하단 생략 -->
위와 같이 기본적으로 생성되는 xml 태그 중 <listener> 태그의 ContextLoaderListener는 /WEB-INF/ 하위의 root-context.xml을 읽어옵니다. root-context.xml은 사용되는 목적이 위의 Application-layer.xml과 동일합니다.
* 여기서 한가지 의문은 Application-layer.xml은 비지니스 레이어 부분인데 WEB-INF 밑에 있는 것이 좋을지에 대한 생각이 들었습니다. 비지니스 로직은 결국 서버측에서 로직을 실행 하기 때문에 Presentation Layer 보다는 다른 곳으로 분리하여 관리하는 것이 맞다는 생각이 들었습니다.
검색을 해보니 나중에 유지보수 과정에서 비지니스 컴포넌트를 수정하고 테스트를 진행하기 위해서는 src/main/resources 경로 하위에 xml을 위치하는 것이 좋다고 한다. 그렇게 하면 src/test/java 폴더에 테스트 클라이언트 프로그램도 작성 가능하기 때문입니다.
* web.xml 수정
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- <param-value>/WEB-INF/spring/root-context.xml</param-value> -->
<!-- classpath: src/main/resources/ 의 경로를 의미합니다. -->
<param-value>classpath:root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
결과적으로 ContextLoaderListener는 <context-param> 의 <param-value>의 값을 읽어들여서 비지니스 컴포넌트를 실행합니다. 이와 같이 기본 생성시 설정되는 xml 파일도 수정이 가능하다는 것이 이번 포스팅의 핵심입니다.
기본적인 스프링 컨테이너의 관계
1) Tomcat Server를 처음 구동 할 때 web.xml 파일을 읽어들여서 서블릿 컨테이너가 구동됩니다.
2) 서블릿 컨테이너는 web.xml 파일에 등록된 ContextLoaderListener 객체를 생성(Pre-Loading) 합니다.
* ContextLoaderListener 객체는 src/main/resources 폴더의 root-context.xml 파일을 로딩합니다. 이때 Service 구현 클래스나 DAO 객체들이 메모리에 생성됩니다.
3) 특정 요청(ex *.do) 을 클라이언트에서 서버로 요청 할 때 서블릿 컨테이너는 DispatcherServlet 객체를 생성하고 DispatcherServlet 객체는 /WEB-INF/ 하위의 위치한 특정 경로의 Presentation-layer.xml 파일을 로딩하여 두 번째 스프링 컨테이너를 구동합니다. 이 때 두 번째 스프링 컨테이너가 Controller 객체를 메모리에 생성합니다.
4) ContextLoaderListener가 생성하는 스프링 컨테이너를 ROOT 컨테이너라고 하며 쉽게 부모 컨테이너라고 생각하면 됩니다.
그리고 DispatcherServlet이 생성한 컨테이너는 ROOT 컨테이너가 생성한 객체를 이용하는 자식 컨테이너가 됩니.
따라서 부모 컨테이너가 생성한 비즈니스 객체를 자식 컨테이너가 생성한 Controller에서 참조하여 사용할 수 있습니다.