(스프링) 스프링 MVC 프레임워크 동작방식

*src/main/webapp/WEB-INF/web.xml 파일에 DispatcherServlet를 설정한다.


DispatcherServlet은 전달받은 설정 파일을 이용해서 스프링 컨테이너를 생성하는데, HandlerMapping, HandlerAdapter, 컨트롤러, ViewResolver등의 빈은 DispatcherServlet이 생성하는 스프링 컨테이너로부터 구한다.



<servlet>
<servlet-name>dispatcher</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>


<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>




---->contextConfiguration 초기화 파라미터를 설정하지 않은 경우, DispatcherServlet은
WEB-INF/[서블릿이름]-servlet.ml 파일을 설정파일로 사용한다.
여기서는 다음과 같다.
/WEB-INF/spring/appServlet/servlet-context.xml




* @Controller를 위한 HandlerMapping 과 HandlerAdapter


DispatcherServlet은 스프링 컨테이너에서 HandlerMapping과 HandlerAdapter타입의 빈을 사용하므로, 사용하려는 핸들러에 알맞은 HandlerMapping 빈과 HandlerAdapter빈이 스프링 설정에 등록되어 있어야 한다.


servlet-context.xml에 있는  <annotation-driven/>은 매우 다양한 스프링 빈 설정을 추가해준다.
이 태그가 빈으로 추가해주는 클래스 중에는 @Controller타입의 핸들러 객체를 처리하기 위한 다음의 두 클래스도 포함되어 있다.
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter


RequestMappingHandlerMapping 애노테이션은 @Controller애노테이션이 적용된 객체의 @RequestMapping값을 이용해서 웹 브라우저의 요청을 처리할 컨트롤러 빈을 찾는다.

RequestMappingHandlerAdapter애노테이션은 컨트롤러의 메소드를 알맞게 실행하고, 그 결과를 ModelAndView 객체로 변환해서 DispatcherServlet에 리턴한다.



RequestMappingHandlerAdapter 클래스는 "/hello" 요청 경로에 대해 hello()메소드를 호출하는데, 이때 Model객체를 생성해서 첫 번쨰 파라미터로 전달한다.



*JSP를 위한 ViewResolver

컨트롤러의 처리결과를 JSP를 이용해서 생성하려면 ,다음의 설정을 추가해주면된다.

servlet-context.xml에

<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>




컨트롤러의 실행 결과를 받은 DispatcherServlet은 ViewResolver에게 뷰 이름에 해당하는 View객체를 요청하는데, 이떄 InternalResourceViewResolver는 "prefix+뷰이름+suffix"에 해당하는 경로를 뷰 코드로 사용하는 InternalResourceView타입의 VIew 객체를 리턴한다.


DispatcherServlet은 컨트롤러의 실행 결과를 HandlerAdapter를 통해서 ModelAndView 형태로 전달받는다고 했는데, 이 중에서 Model에 해당하는 값을 View객체에 Map형식으로 전달한다. 예를들어 HelloController클래스는 다음과 같이 Model에 "greeting"속성을 설정했었다.

model.addAttribute("greeting","안녕하세요"+name);

이 경우 DispatcherServlet은 View객체에 응답 생성을 요청할 때, greeting키를 갖는데 Map객체를 View객체에 전달한다.


<body>
인사말: ${greeting}
</body>




* 디폴트 핸들러와 HandlerMapping의 우선순위

web.xml 설정을 보면 DispatcherServlet에 대한 매핑 경로를 다음과 같이 '/'로 주었다.


매핑경로가 '/'인 경우, .jsp로 끝나는 요청을 제외한 모든 요청을 DispatcherServlet이 처리하게 된다.
즉, /index.html 이나 /css/bootstrap.css와 같은 요청을 DispatcherServlet이 처리하게 된다.

그런데 <annotation-driven>태그를 통해서 등록되는 HandlerMapping은 @Controller애노테이션이 적용된 빈 객체가 처리할 수 있는 요청 경로만 대응할 수 있다.
예를들어, 등록된 컨트롤러가 한 개 이고 그 컨트롤러가 @RequestMapping("/hello")를 설정하고 있다면, /hello 경로만 처리할 수 있게 된다.
따라서 /index.html 이나 css/bootstrap.css와 같은 요청을 처리할 수 있는 컨트롤러 객체를 찾지못해 DispatcherServlet은 404 응답을 전송하게된다.

/index.html 이나 /css/bootstrap.css와 같은 경로를 처리하기 위한 컨트롤러 객체를 직접 구현해 줄 수도있겠지만, 그것보다는 <default-servlet-handler>설정을 사용하는 것이 좋다.

<default-servlet-handler>태그는 다음의 두 빈 객체를 추가해 준다.
  • DefaultServletHttpRequestHandler
  • SimpleUrlHandlerMapping



DefaultServletHttpRequestHandler는 클라이언트의 모든 요청을 WAS(웹 어플레케이션 서버, 톰캣이나 웹로직 등)가 제공하는 기본 서블릿에 전달한다. 
예를들어, "/index.html"에 대한 처리를 DefaultServletHttpRequestHandler에 요청하면 이 요청을 다시 기본 서블릿에 전달해서 처리하도록 한다. 그리고 SimpleUrlHandlerMapping을 이용해서 모든 경로("/**")를 DefaultServletHttpRequestHandler를 이용해서 처리하도록 설정한다.


<annotationn-drive>태그가 등록하는 RequestMappingHandlerMapping의 적용 우선순위가 <default-servlet-handler>가 등록하는 SimpleUrlHandlerMapping의 우선순위보다 높기 떄문에, 웹 브라우저의 요청이 들어오면 DispatcherServlet은 다음과 같은 방식으로 요청을 처리한다.

  1. RequestMappingHandlerMapping을 사용해서 요청을 처리할 핸들러를 검색한다. 존재하면, 해당 컨트롤러를 이용해서 요청을 처리한다.
  2. 존재하지 않으면, SimplUrlHandlerMapping을 사용해서 요청을 처리할 핸들러를 검색한다. <default-servlet-handler>가 등록한 SimplUrlHandlerMapping은 "/**"경로에 대해 DefaultServletHttpRequestHandler를 리턴한다. DispatcherServlet은 DefaultServletHttpRequestHandler에 처리를 요청한다. DefaultServletHttpRequestHandler는 디폴트 서블릿에 처리를 위임한다.


댓글

댓글 쓰기

이 블로그의 인기 게시물

(ElasticSearch) 결과에서 순서 정렬

(네트워크)폴링방식 vs 롱 폴링방식

(18장) WebSocekt과 STOMP를 사용하여 메시징하기