진짜 개발자
본문 바로가기

FrameWork/Spring MVC

SpringMVC - Spring MVC 동작원리 - 3 (DispatcherServlet이란?, IoC Container 계층 구조)

728x90
DispatcherServlet 이란

 

1. FrontController 패턴?

사용자의 요청을 Servlet에게 전달하기 위해서는 web.xml에 servlet을 등록하고 mapping하는 과정이 필요합니다. 하지만 수 많은 요청이 필요한 어플리케이션의 경우 계속해서 servlet을 등록하고 mapping하는 과정이 필요로하게 됩니다. web.xml을 별도로 관리해주어야 하는 불편함이 있습니다. 이 때문에 새로운 패턴이 생겨났는데요 그것이 바로 FrontController 패턴입니다. 아래의 그림을 보면 조금 더 수월하게 이해하실 수 있을것 같습니다.

 

1.1 기존의 Servlet

기존의 방식은 요청 url당 servlet을 생성하고 그에맞는 Controller에게 요청을 보내주는 코드를 각각 다 따로 작성해야 했습니다.

 

1.2 Front Controller 패턴 적용

FrontController 패턴을 적용하면 하나의 Servlet에서 모든 요청을 받아들여 적절한 Controller로 요청을 위임해줍니다. 물론 적절한 Controller로 위임시켜줄 때에는 또 다시 Command 패턴이란게 필요합니다만, 여기서는 언급하지 않겠습니다.

 

장점

한곳에서 모든 사용자의 요청을 컨트롤할 수 있는것에는 어떤 장점이 있을까요? 기본적으로 사용자의 모든 요청에 대해 인코딩처리, 에러 페이지 처리, 공지 등에 대한 처리를 한곳에서 할 수 있을 것입니다.

 

 

 

2. Dispatcher Servlet

Spring에서는 위와 같은 Front Controller 패턴을 취하는 Servlet을 미리 만들어 두었습니다. 그것이 바로 Dispatcher Servlet입니다. 즉 모든 요청을 한곳에서 받아서 필요한 처리들을 한 뒤, 요청에 맞는 handler로 요청을 Dispatch하고, 해당 Handler의 실행 결과를 Http Response형태로 만드는 역할을 합니다.

 

 

2.1 구조

DispatcherServlet은 앞선 포스팅에서 살펴본 ContextLoaderListener에 의해 ServletContext에 등록된 ApplicationContext를 상속받아 WebApplicationContext를 생성합니다. 위 그림의 Root WebApplicationContext가 ContextLoaderListener에 의해 등록된 ApplicationContext이며 Servlet WebApplicationContext가 그것을 상속받아 DispatcherServlet에서 자동으로 만든 ApplicationContext입니다.

 

 

요약을 하자면 아래와 같습니다.

Root WebApplicationContext

ContextLoaderListener에 의해 ServletContext에 등록되는 ApplicationContext로 모든 Servlet이 사용가능합니다.

 

 

Servlet WebApplicationContext

DispatcherServlet에서 Root WebApplicationContext를 상속받아 만든 ApplicationContext 으로 해당 DispathcerServlet 안에서만 사용이 가능합니다.

 

 

2.2 구조의 이유

위의 그림을 자세히 보시면 Root WebApplicationContext에는 모든 Servlet에서 공용으로 사용가능하게 보이는 Services, Repositories Bean이 등록되어 있는것을 볼 수 있습니다. 때문에, DispatcherServlet이 여러개가 필요한 Application이 있을 수도 있기 때문에, Root WebApplicationContextDispatcherServlet에서 다시 상속을 받아 필요한 기능을 추가하여 사용하도록 구조를 만들어 두었다고 합니다.

 

 

 

3. DispatcherServlet 사용하기

3.1 web.xml 수정

web.xml을 위와 같이 설정하면 됩니다. 우선 이전에 등록했던 helloServlet 설정을 제거합니다.

 

그 다음 DispathcerServlet에서도 Root WebApplicationContext를 상속받아 또 하나의 WebApplicationContext를 만들어 낸다고 말씀 드렸었습니다. 따라서 DispatcherServlet의 <init-param> 태그를 이용해 적절한 ApplicationContext Class를 지정해주고 contextConfigLocation을 알려주어야 합니다.

 

그 후 servlet을 등록하듯이 DispatcherServlet을 등록하고 원하는 url로 매핑하면 됩니다. 위의 경우 /app/*으로 설정하였으므로 /app으로 시작하는 모든 url을 위의 DispatcherServlet이 받아서 처리하게 됩니다.

 

 

3.2 Servlet Configuration Class 생성

web.xml에 등록한 DispatcherServlet의 ApplicationContext의 Configuration Class를 생성해야합니다. AppConfig와 마찬가지로 @Configuration, @ComponentScan을 부여했습니다.

 

 

3.3 Controller 생성

간단한 Controller를 생성합니다. web.xml에 따로 등록하지 않아도 @RestController에 의해 IoC Container에 bean으로 등록될 것이며, DispatcherServlet에 의해 요청이 이 Controller로 전달될 것입니다. 그러나 지금의 구조에는 약간의 문제가 있습니다.

 

<현재 IoC Container 상태>

위의 그림은 현재 IoC Container에 등록된 Bean들의 현황입니다. 앞서서 DispatcherServlet의 구조의 이유를 알아봤을때 Root WebApplicationContext에는 다른 모든 DispatcherServlet에서 공통으로 사용할 수 있는 Service, Repository와 같은 빈들을 등록하고, 그것을 상속받아 DispatcherServlet에서 새로 생성하는 WebApplicationContext에서 Web과 관련된 Controller와 같은 Bean들이 등록되어야 한다고 말씀 드렸었습니다.

 

 

3.4 WebApplicationContext 계층구조 만들기

계층 구조를 만드는 방법은 간단합니다. Root WebApplicationContext에는 Service, Repository 관련 Bean들만을 등록하고 그것을 상속받아 만들어지는 Servlet WebApplicationContext에 웹과 관련된 Controller 등의 Bean들을 등록해주면 됩니다.

 

AppConfig Class 수정

첫째로 Root WebApplicationContext의 설정 파일 Class인 AppConfig를 위와 같이 수정해야 합니다. 설명드리면 @Controller어노테이션이 부여된 Bean들을 제외한 나머지 Bean들만을 등록하겠다는 뜻입니다.

 

WebConfig Class 수정

그 후 Servlet WebApplicationContext의 설정파일 Class인 WebConfig를 수정하여 Controller Bean들만을 등록하도록 해야합니다.

 

<계층구조 적용 후 IoC Container 상태>

위의 그림은 계층 구조를 적용한 후의 ApplicationContext에 등록된 Bean들의 상태입니다. Root WebApplicationContext에는 앞서 말했듯이 모든 DispatcherServlet에서 공통적으로 사용할 수 있는 기능을 가진 Bean들(Service,Repository)등이 등록되고, 그것을 상속 받은 Servlet WebApplicationContext에 웹과 관련된 Bean(Controller)들이 존재하는 것을 볼 수 있습니다.


결과 화면입니다.

 

 

 

4. DispatcherServlet의 IoC Container만을 이용하기

앞선 방법처럼 IoC Container를 계층 구조로 나누어 사용하는 방법도 있지만 그냥 사용하는 방법도 있습니다. 사실 요새는 하나의 DispatcherServlet에서 모든 요청을 받아 처리하는 추세이기 때문에 앞선 방법처럼 계층을 나누는 경우가 드물기도 합니다.

 

방법은 간단합니다. xml에서 앞서 등록했던 listener와 context-param태그를 없애주고, WebConfig class의 @ComponentScan  어노테이션의 옵션만 제거하면 됩니다.