Application Context
- 전체 계층 구조에서 최상단에 위치한 컨텍스트
- 서로 다른 서블릿 컨텍스트에서 공유해야하는 Bean 들을 등록할 수 있다.
- 웹 어플리케이션 전체에 적용 가능한 프로퍼티, DB연결, 로깅 기능에 이용된다.
- Servlet Context에 등록된 Bean은 이용할 수 없다.
- Servlet Context에 동일한 Bean이 있는 경우 Servlet Context의 Bean이 우선 적용된다.
- 하나의 컨텍스트에 적의된 AOP 설정은 다른 컨텍스트의 Bean에는 영향을 미치지 않는다.
Servlet Context
- 서블릿에서만 이용되는 컨텍스트
- 다른 서블릿과 공유하기 위한 Bean들은 Application Context에 등록해놓고 사용해야 한다.
- DispatcherServlet은 자신만의 컨텍스트를 생성, 초기화하고 동시에 ApplicationContext를 찾아서 자신의 부모 컨텍스트로 사용한다.
Component Scan 사용시 컨텍스트 설정 방법
- ApplicationContext에 @Service, @Repository 등록 (Controller는 exclude)
- 즉 Root Application Context, bean factory에 해당 객체가 싱글톤 형태로 저장된다.
- 톰캣 실행시 ContextLoader에 의해 ContextLoader가 실행되어 컨테이너에 의존성 해결을 위한 객체들을 생성하게 된다.
- Servlet Context에 Controller 등록해야 한다. (Service와 Repository는 exclude 하고 Controller는 include한다.)
Context 설정을 위와 같이 한 이유?
- Transaction을 적용하기 위해서.
- 스프링 트랜잭션은 AOP를 이용해서 해당 빈의 proxy를 만들어서 tx가 적용되는 Bean을 바꿔치기한다. 그럼 원래 @Service(또는 @Transactional) 어노테이션이 붙은 빈은 숨고 tx가 적용된 proxy bean이 @Service가 붙은 bean으로 대치된다.
- 만약 Application Context 와 Servlet Context가 모든 타입의 컴포넌트를 풀 스캔할 경우, tx설정은 Application Context에만 적용되기 때문에 Application Context 의 @Service는 트랜잭션 적용이 되지만 Servlet Context 의 @Service 는 트랜잭션 적용이 안된다.
- Bean객체는 Servlet Context 가 우선되므로, @Controller가 동작하여 같은 Context 안에서 검색을 하고, @Service가 지정된 bean이 있으므로 이 bean을 사용한다. 이 @Service가 지정된 bean은 트랜잭션 적용이 안 되어 있어 트랜잭션 처리가 안된다.
DispatcherServlet,ApplicationContext
웹 쪽 자원을 관리하는 DispatcherServlet과 그 외의 자원은 ApplicationContext가 관리한다.
<!-- 전역 파라미터 설정 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring/application-context.xml
</param-value>
</context-param>
<!-- Context Loader Listener -->
<!-- 내부적으로 부모 컨텍스트(ContextLoader) 실행, 이 객체에서 웹과 관련 없는 정보를 저장하는 Root Application context 를 생성한다. -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
xml에서 이런식으로 설정을 하면 applicationContext가 먼저 생성되고 DispatcherServlet은 applicationContext를 부모로 갖는다.
ApplicationContext와 DispatcherServlet에서 Component-scan을 이용해서 등록한 빈은 다른 인스턴스이다. 다만 ApplicationContext에만 등록된 빈의 경우, DispatcherServlet에서 검색해보고 없으면 부모인 ApplicationContext에서 가져온다.
반응형