Spring Framework : web.xml을 통한 WebApplicationContext의 생성

1. web.xml ?

  • web.xml은 WebApplication의 Deployment Descriptor(배포 설명자)이며 XML 형식
  • 애플리케이션의 클래스, 리소스, 구성 및 웹 서버가 이를 사용해서 웹 요청을 처리하는 방법을 기술
  • context.xml에서 WatchedResource를 통해 “WEB-INF/web.xml” 를 수정할 수 있음

2. web.xml 작성 예시

아래와 같은 내용이 일반적으로 등장함.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/*-config.xml</param-value>
</context-param>

<listener>
<display-name>SpringContextLoader</display-name>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

3. ContextLoaderListener 클래스 다이어그램 및 요약

ContextLoaderListener

  • 최초에 웹 애플리케이션이 실행되며 “context-param” 태그로 지정된 “contextConfigLocation”의 값을 읽음
  • “context-param” 태그에 지정된 “ContextLoaderListener” 클래스를 통해 애플리케이션이 구동되었음을 감지
  • “ContextLoaderListener” 는 java의 확장 패키지은 javax에 속해 있는 “ServletContextListener”를 구현함
    • “ServletContextListener”는 서블릿 컨텍스트에 대한 변경 사항에 대해 이벤트 형식으로 받을 수 잇음
  • “ContextLoaderListener” 는 spring-web의 클래스인 “ContextLoader”를 상속함
    • “ContextLoader”는 “Root WebApplicationContext” 를 초기화 하는 작업을 수행

4. ContextLoaderListener 설명

ContextLo``ader.initWebApplicationContext

“ContextLoaderListener”는 단순히 contextInitialized(…) 메서드를 통해 “context-param” 태그로 설정한 값을 전달받아 ContextLoader의 initWebApplicationContext(…)를 호출함.

ContextLoader.initWebApplicationContext

호출된 “initWebApplicationContext” 메서드 내부에는 context를 생성하는 과정을 거쳐 “servletContext”의 Attribute로 생성된 context를 저장. 여기서 해당 context의 저장할 때의 키를 “ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE”로 지정하는 것을 확인.

ContextLoaderListener_concept

결론적으로 정리를 하면 Servlet 컨테이너인 Tomcat이 실행되면서 “ServletContextListener”의 contextInitialized 를 통해 ServletContext를 “ContextLoaderListener”에 전달 하고 이를 다시 “ContextLoader”로 전달이 되고 있음. 이때, “ContextLoader”는 “WebApplicationContext” 를 생성하여 ServletContext의 속성으로 Root Context로 설정함.

6. DispatcherServlet 클래스 다이어그램 및 요약

DispatcherServlet

  • web.xml의 “servlet” 태그에 있는 서블릿을 등록
  • 최초 서블릿이 등록이 될 때, GenericServlet의 “+init(..config)” 메서드를 호출하며 ServletConfig를 매개변수로 전달
  • ServletConfig에는 “contextConfigLocation”의 값인 “classpath:spring/dispatcher-servlet.xml” 값을 갖고 있음
  • GenericServlet의 “+init(..config)”은 내부적으로 “init()”을 호출하며 이는 HttpServletBean가 구현함
  • HttpServletBean의 “init()”은 내부적으로 bean 프로퍼티를 설정을 완료 후 “#initServletBean()” 를 호출하며 해당 메서드는 FrameworkServlet에 구현
  • FrameworkServlet의 “#initServletBean()”를 통해 WebApplicationContext가 생성되며 생성된 WebApplicationContext의 부모로 context로 Root Context를 설정

7. DispatcherServlet 설명

GenericServlet.init

“Servlet”를 구현한 클래스는 서비스에 배치되는 시점에 서블릿 컨테이너가 “init(..config)” 메서드 메서드를 호출함. 여기서 GenericServlet이 이 메서드를 구현함. 내부적으로 이때 ServletConfig 정보가 넘어오며 서브릿을 구성하기 위한 정보와 더불어 web.xml에서 작성한 서블릿의 “contextConfigLocation” 정보도 넘어옴. 게다가 내부적으로 “init()”를 호출하며 해당 메서드는 HttpServletBean 클래스에서 구현함을 확인.

HttpServletBean.init()

초기 파라메터의 값을 활용하여 bean 설정을 위한 프로퍼티를 설정. 설정이 완료된 이후에 “#initServletBean()” 메서드를 호출함. 해당 메서드는 FrameworkServlet 클래스에서 구현함.

FrameworkServlet.initServletBean()

FrameworkServlet의 “#initServletBean()” 메서드는 내부적으로 “#initWebApplicationContext()”를 호출하며 WebApplicationContext를 생성함 이때 내부적으로 “#createWebApplicationContext(…)”를 호출하여 생성함.

FrameworkServlet.initServletBean()

“#createWebApplicationContext(…)”는 매개변수로 ApplicationContext 받음. ApplicationContext로 Root Context가 전달되며 이를 Parent Context로 설정.

8. 최종 정리

ServletContext를 통한 WebApplicationContext 설정

결과적으로 ServletContext는 최초에 실행되는 ContextLoaderListener를 넘어 DispatcherServlet 까지 전달이 되며 이를 통해 내부적으로 부모와 자식관계의 Context를 형성함.

ServletContext를 통한 WebApplicationContext 설정

WebApplicationContext는 BeanFactory를 상속받아 “+getBean(name)”와 같은 bean을 반환하는 메서드를 갖고 있음.

ServletContext를 통한 WebApplicationContext 설정

“+getBean(name)” 메서드는 내부적으로 BeanFactory를 호출하여 bean을 반환하고 있음. 여기서 BeanFactory는 AbstractBeanFactory 클래스를 상속받은 DefaultListableBeanFactory 클래스이며 부모 BeanFactory를 갖고 있음.

ServletContext를 통한 WebApplicationContext 설정

DefaultListableBeanFactory 클래스의 getBean은 자신이 소유한 bean에서 먼저 인스턴스를 찾고 만약 없을 경우 부모 BeanFactory에서 찾아서 반환하는 것을 확인할 수 있음.

결국 Root Context와 자식 Context와 부모와 지삭의 관계를 맺으며 자식 BeanFactory는 부모의 BeanFactory에서 자원을 공유할 수 있음. 단, 반대로 부모 BeanFactory에서 자식의 BeanFactory를 공유하지는 않음.