최근 '토비의 스프링 Vol2'를 읽으며 web.xml 에 루트, 서블릿 어플리케이션 컨텍스트를 등록하는 과정을 읽게 되었다. 회사에서 Spring을 활용하고 있음에도, 실제로 이미 구성된 web.xml을 면밀히 살펴보지 않았기에 이번 글에서는 이러한 부분들을 학습하고 정리하고자 한다.
Spring 의 웹 어플리케이션은 두 개의 어플리케이션 컨텍스트가 존재한다.
서블릿 어플리케이션 컨텍스트
루트 어플리케이션 컨텍스트
루트 어플리케이션 컨텍스트는 Spring 응용 프로그램의 전역적인 컨텍스트로서, 주로 서비스, 데이터 액세스 객체, 인프라스트럭처 빈 등과 같은 Spring의 핵심적인 Bean들을 포함한다.
사용자가 정의한 비즈니스 로직을 담고 있는 Bean 들도 이 컨텍스트에 등록되어 있으며, 이러한 구성 요소들은 전체 애플리케이션에서 공유되어 필요에 따라 서블릿 어플리케이션 컨텍스트에도 접근할 수 있다.
웹 애플리케이션 레벨에 만들어지는 루트 웹 애플리케이션 컨텍스트를 등록하는 가장 간단한 방법은 서블릿의 이벤트 리스너를 이용하는 것이다.
스프링은 웹 애플리케이션의 시작과 종료 시 발생하는 이벤트를 처리하는 리스너인 ServletContextListener를 이용하며, 이를 상속한 ContextLoaderListener 를 사용한다.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
web.xml 에 작성한다.
실제로 이를 상속받고 있다.
ContextLoaderListener 는 웹 어플리케이션 시작 시 자동으로 루트 어플리케이션 컨텍스트를 만들고 초기화한다. 이때 사용하는 디폴트 설정 파일은 아래와 같다.
이 디폴트 값을 바꾸고 싶다면 contextConfigLocation 파라미터를 추가하여 아래와 같이 작성한다.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/daoContext.xml
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
클래스패스의 경로에 있는 설정파일을 사용할 경우 아래와 같이 작성한다.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-context.xml
classpath:mvc-context.xml
</param-value>
</context-param>
ContextLoaderListener가 자동으로 생성하는 컨텍스트의 클래스는 기본적으로 XmlWebApplicationContext 이다. 다른 구현체로 변경하기 위해서는 contextClass 파라미터를 이용해 지정해주면 된다.
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
위와 같이 설정 시, 루트 어플리케이션 컨텍스트의 구현체 클래스는, AnnotationConfigWebApplicationContext 이다.
스프링의 웹 기능을 지원하는 프론트 컨트롤러 서블릿은 DispatcherServlet이다. 서블릿 이름을 다르게 지정해주면 하나의 웹 애플리케이션에 여러 개의 DispatcherServlet을 등록할 수도 있다.
각 DispatcherServlet은 서블릿이 초기화될 때 자신만의 컨텍스트를 생성하고 초기화한다. 동시에 웹 애플리케이션 레벨에 등록된 루트 애플리케이션 컨텍스트를 찾아서 이를 자신의 부모 컨텍스트로 사용한다
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
DispatcherServlet에 의해 만들어지는 애플리케이션 컨텍스트는 모두 독립적인 네임스페이스를 갖게 된다. 이 네임스페이스는 서블릿 단위로 만들어지는 컨텍스트를 구분하는 키가 된다.
네임스페이스는 servlet-name 태그로 지정한 서블릿 이름에 servlet을 붙여서 만든다. 서블릿 이름이 spring이라면 네임스페이스는 spring-servlet이 된다.
Spring 에서 등록된 서블릿을 언제 만들고 초기화할지 순서를 정의하며, 여러 Servlet 이 등록될 경우 작은 수를 갖고 있는 순서대로 초기화 한다. 음수일 경우 임의의 순서대로 초기화 한다.
다른 Servlet 을 사용하지 않을 경우 보통 1을 사용한다.
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/spring-servlet.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
위를 통해 루트 어플리케이션 컨텍스트가 구성되며, 초기화 및 구성되며 등록되는 빈은 DAO, 인프라스트럭쳐 Bean, 서비스 Bean, 사용자 비지니스 Bean 들이 등록된다.
서블릿 어플리케이션 컨텍스트는 spring MVC 를 구성하기 위해 사용되는 Bean 들이며, DispatchServlet 이 서블릿 어플리케이션 컨텍스트를 자체적으로 갖고 있다. 등록되는 빈은 컨트롤러, 핸들러 어댑터, 핸들러 매핑, 뷰 리졸버 등이 있다.
출처: 토비의 스프링 vol2