Spring
에서 제공하는 서블릿 기반의 웹 프레젠테이션 계층 프레임워크가 Spring MVC
다.
How Spring MVC works
를 주제로 두 개의 글로 나눠서 정리할 예정이고, 첫 번째 글인 이번 글에서는 WebApplicationContext
, Context Hierarchy
중심으로 스프링 애플리케이션이 웹 환경에서 스프링 컨테이너가 어떻게 구성되는 지를 다룰 예정이다.
Spring
에서는 웹 환경에서 사용하기 위해 IoC Container
중 하나인 WebApplicationContext
를 제공하면서 의도적으로 웹 애플리케이션의 컨텍스트를 두 가지로 분리했다.
[ 그림 1 ] 은 Spring MVC
공식 문서에서 제공한 자료인데, 앞서 언급한 두 가지 애플리케이션 컨텍스트를 볼 수 있다. 웹 애플리케이션 컨텍스트를 두 가지로 분리한 이유는 토비의 스프링에서 다음과 같이 설명한다.
이렇게 스프링 컨텍스트를 두 가지로 분리해둔 이유는 스프링 웹 서블릿 컨텍스트를 통째로 다른 기술로 다른 기술로 대체할 수 있도록 하기 위해서다.
스프링 웹 서블릿 컨텍스트를 통째로 다른 기술로 대체하는 것과 스프링 컨텍스트를 분리하는 것이 어떤 의미가 있을까?
[ 그림 1 ] 을 통해 Servlet WebApplicationContext
의 특징을 한 번 찾아보자.
- Servlet Web Application 컴포넌트 (Controller, ViewResolver, HandlerMapping)를 저장한다.
- Root WebApplicationContext에 의존한다.
Servlet WebApplicationContext
는 이름 그대로, 서블릿 기반의 웹 애플리케이션의 컴포넌트를 관리하기 위한 컨테이너 역할을 담당한다. 만약 서블릿 기반의 웹 애플리케이션이 아닌 경우에는 별도의 다른 컨텍스트가 필요할 것이다. 즉, Servlet WebApplicationContext
는 웹 계층 기술이 대체될 경우 더 이상 사용하지 않는 대상이 될 수 있다는 것이다.
반면, Root WebApplicationContext
는 서비스, 데이터 액세스 계층을 담고 있고 이는 웹 계층 기술의 종류와 상관 없이 웹 계층에서 의존하는 대상이다.
정리하자면, 웹 계층의 기술이 다른 기술로 대체 되어도 웹 계층에서 (심지어 스프링에서 제공하지 않는 웹 계층 기술이어도) 스프링 기술이 적용된 서비스, 데이터 액세스 계층에 접근하는 구조를 일관성있게 만들기 위해 스프링 컨텍스트를 두 가지로 분리했다고 이해할 수 있다.
[ 그림 3 ] 에서 Delegates if no bean found
는 어떤 맥락에서 나온 것일까? 결론부터 말하면 Container Hierarchy
에서 나온 내용이다.
토비의 스프링에서 Context Hierarchjy
가 필요한 상황을 아래와 같이 설명한다.
빈을 담아둘 IoC 컨테이너는 애플리케이션마다 하나씩이면 충분하다. 빈의 개수가 많아져서 설정파일이 커지는 게 문제라면 파일을 여러 개로 쪼개서 만들고 하나의 애플리케이션 컨텍스트가 여러 개의 설정 파일을 사용하게 하면 그만이다. 하지만 한 개 이상의 IoC 컨테이너를 만들어두고 사용해야 할 경우가 있다. 바로 트리 모양의 계층구조를 만들 때다.
여기서 말하는 트리 모양의 계층구조
는 이미 우리가 위에서 다룬
Servlet WebApplicationContext
, Root WebApplicationContext
관계를 통해서 확인 했다.
트리 구조의 계층을 생각 했을 때 [ 그림 4 ] 를 예로 들 수 있다. 각각의 컨텍스트는 별도의 독립적인 설정 정보를 기반으로 빈 오브젝트를 생성하고 관리하는데, DI를 위해서 빈을 검색 할 때는 검색 범위를 부모 애플리케이션 컨텍스트까지 넓힌다. 가장 먼저 자신이 관리하는 컨텍스트에서 찾고 대상 빈 오브젝트가 있는 경우에는 검색을 멈춘다. 하지만 자신이 관리하는 컨텍스트 내에 찾는 빈이 없는 경우에는 부모 애플리케이션 컨텍스트에 요청을 한다. 단, 루트 애플리케이션 컨텍스트까지 빈 검색을 요청했음에도 찾지 못한 경우에는 검색을 중단한다.
Delegates if no bean found
를 찾는 빈이 없는 경우 루트 애플리케이션 컨텍스트에 요청을 보내는 것으로 이해할 수 있다. 근데 Context Hierarchy
를 사용하는 이유가 뭘까? 토비의 스프링에서 계층 구조를 사용하는 이유를 아래와 같이 설명한다.
미리 만들어진 애플리케이션 컨텍스트의 설정을 그대로 가져다가 사용하면서 그중 일부 빈만 설정을 변경하고 싶다면, 애플리케이션 컨텍스트를 두 개 만들어서 하위 컨텍스트에서 바꾸고 싶은 빈들을 다시 설정해줘도 된다. 이렇게 기존 설정을 수정하지 않고 사용하지만 일부 빈 구성을 바꾸고 싶을 경우, 애플리케이션 컨텍스트의 계층구조를 만드는 방법이 편리하다.
애플리케이션 안에 성격이 다른 설정을 분리해서 두 개 이상의 컨텍스트를 구성하면서 각 컨텍스트가 공유하고 싶은게 있을 때 계층구조를 이용한다.
위에서 언급한 이유 중 2)
이
Servlet WebApplicationContext
, Root WebApplicationContext
관계가 계층구조로 구성된 이유를 설명한다.
[ 그림 1 ] 을 보면, DispatcherServlet
내부에 두 컨텍스트가 모두 포함되어 있는 것 처럼 묘사됐지만 사실 DispatcherServlet
즉, 서블릿 레벨에서는 Servlet WebApplicationContext
를 관리하고, 애플리케이션 레벨에서 Root WebApplicationContext
를 관리한다. 하나의 웹 애플리케이션에서 DispatcherServlet
는 두 개 이상 존재할 수 있는데, 이 때 각 DispatcherServlet
별로 독립된 WebApplicationContext
를 생성해서 관리한다.
DispatcherSevlet
이 두 개 일 때 [ 그림 5 ] 와 같이 표현될 수 있고, 이 때 계층 구조를 활용해서 공유 자원은 Root WebApplicationContext
에서 관리해서 각각의 Servlet WebApplicationContext
에서 활용할 수 있도록 할 수 있다. (계층 구조를 이용하는 이유)
하지만, [ 그림 1 ] 에서 표현된 것 처럼 일반적으로 DispatcherServlet
하나만 운용한다. DispatcherServlet
이 하나만 있어도 모든 요청을 처리할 수 있기 때문이다. 그러면 계층 구조를 사용할 의미가 없지 않은가? 계층 구조를 왜 사용하지? 라는 생각을 할 수 있다.
이 질문에 대한 답을 토비의 스프링에서는 다음과 같이 설명한다.
그 이유는 전체 애플리케이션에서 웹 기술에 의존적인 부분과 그렇지 않은 부분을 구분하기 위해서다. 스프링을 이용하는 웹 애플리케이션이라고 해서 반드시 스프링이 제공하는 웹 기술을 사용해야 하는 것은 아니다. 데이터 액세스 계층이나 서비스 계층은 스프링 기술을 사용하고 스프링 빈으로 만들지만 웹을 담당하는 프레젠테이션 계층은 스프링 외의 기술을 사용하는 경우도 종종 있기 때문이다.
스프링 웹 애플리케이션이 어떻게 스프링 컨테이너를 구성하고 사용하는 지에 대해서 큰 틀에서 알아봤다. 다음 글에서는 Spring MVC
핵심 요소인 DispatcherServlet
을 중심으로 Spring MVC
구성하는 컴포넌트 및 내부 동작 원리에 대해서 다뤄볼 예정이다.
토비의 스프링 Vol. 1 | 1.4 제어의 역전 (IoC)
토비의 스프링 Vol. 2 | 1.5 스프링의 IoC
토비의 스프링 Vol. 2 | 1.1 IoC 컨테이너: 빈 팩토리와 애플리케이션 컨텍스트
Web on Servlet Stack
Tomcat, Spring MVC의 동작 과정