스프링 MVC 아키텍처를 살피면, "DispatcherSevlet" 이라는 용어가 매번 나온다. 내가 아는 범위에서는 dispatcher 라는 것은 준비상태에 있는 작업을 실행상태로 전환하는 역할을 하는 것으로 알고 있다. 하지만 스프링에서의 dispatcher는 ?



누군가가 DispatcherServlet 뭔데?



라고 묻는다면 나는 당연히 대답 못하겠지. 그래서 참고링크의 글을 따왔고 궁금증은 계속 수정해나가면서 해당 게시글을 개선해나갈 생각이다.


DispatcherServlet

  • Spring MVC Framework의 유일한 Front Controller인 DispatcherServlet은 Spring MVC의 핵심요소이다. 

  • DispatcherServlet은 Controller로 향하는 모든 웹 요청의 진입점이며, 웹 요청을 처리하며, 결과 데이터를 Client에게 응답한다.

  • DispatcherServlet은 Spring MVC의 웹요청 Life Cycle을 주관한다고 할 수 있다.

스프링 MVC는 DispatcherSevlet 등장으로 web.xml의 역할이 축소되었다. 예전에는 서블릿 URL로 활용하기 위해 반드시 web.xml에 등록해주었지만, DispatcherServlet의 등장으로 해당 애플리케이션에 들어오는 요청을 모두 핸들링해줄 수 있기 때문이다.


그러나 여전히 web.xml의 중요성은 큰데 왜냐하면 servlet 으로 DispatcherServlet 을 등록해주어야 하며,  해당 객체의 URL 적용범위또한 web.xml에서 설정해주어야 하기 때문이다. 이후에 고급서비스를 위한  <filter> 혹은 <listener> 를 등록하는 역할 또한 web.xml의 기능으로 남아있다. 


필터관련 처리를 생각하면 대표적인 UTF-8 인코딩 처리를 생각해보면 된다. JSP 페이지에서 한글 깨짐 문제 때문에 우리는 항상 web.xml에 해당 필터 내용을 추가하지 않는가. 


web.xml에서 맡고 있는 <servlet> 매핑의 역할은 이제 DispatcherServlet으로 넘어갔다고 생각하자. web.xml에 DispatcherServlet의 <url-pattern> 을 " / " 로 설정함과 동시에 이제 모든 요청은 DispatcherServlet 의 영역이 되어버린 것이다. 


물론 web.xml에 계속 서블릿을 매핑해줄수 있지만 이러한 방식을 버리고 DispatcherServlet을 이용해 웹개발을 좀 더 유용하며 간결할 것이라 생각한다. 


아래는 실제 본인 프로젝트에 존재하는 web.xml의 내부 코드이다. 


DispatcherServlet이 WebApplicationContext를 생성할 수 있도록 빈(Bean) 정보가 들어있는 파일들도 설정해주어야 한다. 


빈 설정 파일을 하나 이상을 사용하거나, 파일 이름과 경로를 직접 지정해주고 싶은 경우에 contextConfigLocation 라는 초기화 파라미터 값에 빈 설정 파일 경로를 설정해준다.


아래의 내용을 설명하면 스프링프로젝트가 실행되면서 web.xml을 위에서 차례로 태그를 해석한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
 
 
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
 
 
<!-- Processes application requests -->
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
    
<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>            
cs



- DispatcherServlet 의 역할

DispatcherServlet을 이용한다는 것은 스프링에서 제공하는 @MVC를 이용하겠다는 말과 일맥상통한다. MVC(Model / View / Controller)의 설계영역을 완전히 분할하여 개발자가 MVC 패턴에 맞게끔 애플리케이션을 개발하도록 유도하는 방식이다. 


내가 참고한 링크에서 DispatcherServlet를 아래와 같이 정의하고 있었다.


Model, Controller, View 의 각각의 영역을 

조합하여 브라우저로 출력해주는 역할을 수행하는 클래스 




[ 출처 : http://pds21.egloos.com/pds/201202/24/49/d0144949_4f47a0b19ed33.png ]



위의 처리과정의 대부분은 컨테이너가 대신 작업해주며, 개발자가 직접 구현해야할 부분은 많지 않다. 다만 위의 작업 흐름을 스스로 개발하면서 체감하고 있어야 한다. 클라이언트는 웹 클라이언트, 브라우저(IE, Chrome, Opera. Firefox ...) 등을 말한다.


작업흐름


(1) 클라이언트가 해당 애플리케이션에 접근하고, URL을 요청하면 해당 요청을 Dispatcher-Servlet이 중간에 가로챈다. 이렇게 가로채는 이유는 앞서서 web.xml에 DispatcherServlet의 <url-pattern> 이 " / " 와 같이 해당 애플리케이션의 모든 URL로 등록되었기 때문이다. 만약 특정 URL로 적용하고 싶다면 <url-pattern>의 내용을 바꿔주어 범위를 변경시키면 된다.


(2) 가로챈 정보를 HandlerMapping에게 보내 해당 요청을 처리할 수 있는 Controller를 찾는다. 


(3) HandlerMapping이 해당 요청을 처리할 수 있는 Controller를 찾아낸다면 클라이언트의 요청을 해당하는 Controller에게 보내주게 된다. Controller는 개발자가 직접 구현해야 하는 부분이다.


(4) Controller는 해당 요청을 처리한 후 응답할 경우 View의 이름을 리턴하게 되는데, 리턴되는 view 이름을 ViewResolver가 먼저 받아 해당되는 View가 존재하는지 검색한다.


(5) 해당 View가 존재한다면, 처리결과를 View에 보낸 후, 처리 결과가 포함된 View를 다시 DispatcherServlet에게 보내주게 된다.


(6) DispatcherSevlet은 View로부터 받은 처리결과를 클라이언트에게 전송한다.


현재까지의 내용으로는 DispatcherServlet(이하 디스패처-서블릿) 을 이용하면서 조심스러워야 할 부분이 없다고 생각하지만, 모든 요청을 디스패처-서블릿이 받고 해당 요청을 Controller(이하 컨트롤러) 에게 넘겨주면 문제가 생긴다. 

따라서 위의 문제를 해결할 방법이 두 가지 존재한다고 한다. 

(1) 디스패처서블릿이 처리할 URL과 자바와 연관이 없는 리소스를 분리
/apps - 클라이언트가 이 URL로 접근하면 디스패처-서블릿이 담당
/resources - 해당 URL은 디스패처-서블릿이 컨트롤할 수 없는 영역으로 분리

(2) 모든 요청을 컨트롤러에 등록
매우 큰 위험부담이 따른다.

하지만 위의 (1) 해결방법은 코드가 지저분해질뿐만 아니라, apps라는 URL을 붙여주어야 하기 때 직관적인 설계가 힘들다는 단점이 있고 (2) 해결방법은 모든 요청을 컨트롤러에 등록하지만, 소규모 애플리케이션에서만 해결되는 이야기이다. 

하지만 스프링은 이런 문제들은 해결함과 동시에 편리한 방법을 고안했다.

<mvc:resource /> 

아래의 내용은 servlet-context.xml에서 확인이 가능하다.

1
2
3
<!-- Handles HTTP GET requests for /resources/** by efficiently 
serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
cs

이 전략은 먼저 디스패처서블릿을 통해 들어온 요청을 처리하는데, 해당 요청에 대한 컨트롤러를 찾을 수 없다면 2차적으로 위의 설정된 경로를 검색하여 해당 자원을 찾아내는 것이다. 


Posted by doubler
,