본문 바로가기

spring

Spring MVC 구조 - (하)

  • Spring MVC 수행 흐름

strtus를 비롯한 대부분의 MVC 프레임워크는비슷한 구조를 가졌다. 따라서 하나의 프레임워크만 잘 이해한다면 다른 프레임워크도 쉽게 이해할 수 있다. 우리는 앞에서 Spring MVC 구조가 전혀 새롭지는 않을 것이다.

 

그림 5 - 1은 클라이언트의 요청을 시작으로 Spring MVC를 구성하는 각 요소가 어떻게 동자갛는지를 표현했으며, 각 번호에 대한 설명을 아래에 추가했다. 그림의 번호와 설명을 번갈아 가며 확인하기 바란다.

 

스프링 MVC의 수행 흐름

1. 클라이언트로부터 모든 ".do" 요청을 DispatcherServlet이 받는다.

2. DispatcherServlet은 HandlerMapping을 통해 요청을 처리할 Controller를 검색한다.

3. DispatcherServlet은 검색된 Controller을 실행하여 클라이언트의 요청을 처리한다.

4. Controller는 비즈니스 로직의 수행 결과로 얻어낸 Model 정보와 Model을 보여줄 View 정보를 ModelAndView 객체에 저장하여 리턴한다.

5. DispatcherServlet은 ModelAndView로부터 View 정보를 추출하고, ViewResolver를 이용하여 응답으로 사용할 View를 얻어낸다.

6. DispatcherServlet은 ViewResolver를 통해 찾아낸 View를 실행하여 응답을 전송한다.

 

Spring MVC의 구조와 수행 흐름이 현재 BoardWeb 프로젝트에 적용된 Controller 구조와 유사하다는 것을 느낄 것이다. 유일하게 다른 점 하나가 Controller의 리턴타입이 String이 아닌 ModelAndView로 바뀐 것인데, 이 ModelAndView의 기능에 대해서는 앞으로 천천히 알아가도록 하자.

 

 

  • DispatcherServlet 등록 및 스프링 컨테이너 구동
  • DispatcherServlet 등록

Spring MVC에서 가장 중요한 요소가 모든 클라이언트의 요청을 가장 먼저 받아들이는 DispatcherServlet이다. 따라서 Spring MVC 적용에서 가장 먼저 해야할 일은 WEB-INF/web.xml 파일에 등록된 DispatcherServlet 클래스를 스프링 프레임워크에서 제공하는 DispatcherServlet으로 변경하는 것이다.

 

[web.xml]

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet<servlet-class>
    <servlet>
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

 

DispatcherServlet 클래스를 스프링에서 제공하는 DispatcherServlet으로 변경한 것을 제외하면 달라진것은 없다. web.xml 파일을 수정했으면 톰캣 서버를 재구동하고, login.jsp 파일을 실행한다. 로그인 화면이 브라우저에 출력되겠지만 아직 서블릿 컨테이너는 반응하지 않는다. 서블릿 컨테이너는 클라이언트의 ".do" 요청이 있어야 DispatcherServlet 객체를 생성한다. 로그인 정보를 적절히 입력하고 로그인 버튼을 클릭하면 다음과 같은 내용이 콘솔에 출력된다.

 

정보 : Initializing Spring FrameworkServlet 'action'
INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet

org.springframework.beans.factory.BeanDefinitionStoreException : IOException

클라이언트가 로그인 버튼을 클릭하면 "login.do" 요청을 서버에 전달하면 서블릿 컨테이너는 web.xml 파일에 action이라는 이름으로 등록된 DispatcherServlet 클래스의 객체를 생성한다.

 

  • 스프링 컨테이너 구동

클라이언트의 요청으로 DispatcherServlet 객체가 생성되고 나면 DispatcherServlet 클래스에 재정의된 init() 메소드가 자동으로 실행되어 XmlWebApplicationContext라는 스프링 컨테이너가 구동된다. XxmlWebApplicationContext는 ApplicationContext를 구현한 클래스 중 하나이다. 하지만 XmlWebApplicationContext는 우리가 직접 생성하는 것이 아니라 Dispatcherservlet이 생성한다.

 

Spring MVC의 구성 요소 중에서 DispatcherSerlvet 클래스가 유일한 서블릿이다. 따라서 서블릿 컨테이너는 web.xml 파일에 등록된 DispatcherServlet만 생성해준다. 하지만 DispatcherServlet 객체 혼자서는 클라이언트의 요청을 처리할 수 없고, 반드시 HandlerMapping, Controller, ViewResolver 객체들과 상호작용해야 한다. 이 객체들을 메모리에 생성하기 위해서 DispatcherServlet은 스프링 컨테이너를 구동하는 것이다.

 

우리가 직접 DispatcherServlet 클래스를 개발했을 때는 init() 메소드에서 DispatcherServlet이 사용하는 HandlerMappping, Controller, ViewResolver 객체들을 생성한다. 다만, 스프링에서 제공하는 DispatcherServlet은 스프링 컨테이너를 통해 이 객체들을 생성하는 것이 다를 뿐이다.

 

public class DispatcherServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private HandlerMapping handlerMapping;
    private ViewResolver viewResolver;
    
    public void init() throws ServletException {
        handlerMapping = new HandlerMapping();
        viewResolver   = new ViewResolver();
        viewResolve.setPrefix("./");
        viewResolver.setSuffix(".jsp");
    }
}

 

결국 DispatcherServlet은 클라이언트의 요청 처리에 필요한 HandlerMapping, Controller, ViewResolver 객체들을 생성하기 위해 스프링 컨테이너를 구동한다. 이 과정을 표현하면 아래 그림과 같다.

 

스프링 컨테이너(XmlWebApplicationContext)의 구동과정

 

서블릿 컨테이너가 DispatcherServlet 객체를 생성하고 나면 재정의된 init() 메소드가 자동으로 실행된다. 그러면 init() 메소드는 스프링 설정 파일(action-servlet.xml)을 로딩하여 XmlWebApplicationContext를 생성한다. 즉, 스프링 컨테이너가 구동되는 것이다. 결국 스프링 설정 파일(action-servlet.xml)에 DispatccherServlet이 사용할 HandlerMapping, Controller, ViewResolver 클래스를 <bean> 등록하면 스프링 컨테이너가 해당 객체들을 생성해준다. 

 

  • 스프링 설정파일 등록

현재 상태에서는 DispatcherServlet이 스프링 컨테이너를 구동할 때 무조건 /WEB-INF/action-servlet.xml 파일을 찾아 로딩한다. 그런데 해당 위치에 action-servlet.xml 파일이 없어서 FileNotFoundException이 발생한다. 그런데 해당 위치에 action-servlet.xml 파일이 없어서 FileNotFoundException이 발생한다. DispatcherServlet은 Spring 컨테이너를 구동할 때, web.xml 파일에 등록된 서블릿 이름 뒤에 '-servlet.xml'을 붙여서 스프링 설정파일을 찾는다. 따라서 web.xml 파일에 등록된 DispatcherServlet 이름이 dispatcher였다면 '/WEB-INF/dispatcher-servlet.xml' 파일을 찾았을 것이다.

 

이제 DispatcherServlet이 스프링 컨테이너를 구동할 때 로딩할 스프링 설정 파일을 추가하자. 이클립스의 프로젝트 탐색 창에서 WEB-INF 폴더에 마우스 오른쪽 버튼을 클릭하여 [New] -> [Other] 메뉴를 선택한다. 그리고 Spring 폴더에서 'Spring Bean configuration file'을 선택하고 <Next>를 클릭한다.

 

'File name'에 "action-servlet.xml" 파일명을 입력하고 <Finish>를 클릭하면 WEB-INF 폴더에 action-servlet.xml 파일이 생성된다.

 

  • 스프링 설정파일 변경

DispatcherServlet은 자신이 사용할 객체들을 생성하기 위해서 스프링 컨테이너를 구동한다. 이때 스프링 컨테이너를 위한 설정 파일의 이름과 위치는 서블릿 이름을 기준으로 자동으로 결정된다. 하지만 필요에 따라서는 설정 파일의 이름을 바꾸거나 위치를 변경할 수도 있다. 이때 서블릿 초기화 파라미터를 이용하면 된다. 우선 WEB-INF 폴더 아래 config 폴더를 새로 만들고, action-servlet.xml 파일을 옮긴다. 그리고 파일이름을 "presentation-layer.xml"으로 변경한다.

 

그리고 web.xml 파일을 열어서 DispatcherServlet 클래스를 등록한 곳에 <init-param> 설정을 추가한다. 이때, <param-name> 엘리먼트로 지정한 contextConfigLocation은 대소문자를 구분하므로 정확하게 등록해야 한다.

 

[web.xml]

<servlet>
    <servlet-name>action</servlet-name>
    <servlet-config>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/presentation-layer.xml</param-value>
    <init-param>
</servlet>

<servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

 

이렇게 DispatcherServlet을 설정하면 서블릿 컨테이너가 DispatcherServlet 객체를 생성한 후, 다음과 같이 init() 메소드를 호출한다. 그리고 contextConfigLocation이라는 파라미터로 설정한 정보를 추출하여 스프링 컨테이너를 구동할 때 사용한다.

 

public class DispatcherServlet extends HttpServlet {
    private String contextConfigLocation;
    
    public void init(ServletConfig config) throws ServletException {
        contextConfigLocation = config.getInitParameter("contextConfigLocation");
        new XmlWebApplicationContext(contextConfigLocation);
    }
}

 

서버를 재구동하고 로그인 버튼을 다시 클릭한 후 콘솔에 출력된 로그 메시지를 확인해보면 우리가 등록한 스프링 설정 파일을 로딩한느 것을 확인할수 있다.

 

<실행결과>

[WEB-INF/config/presentation-layer.xml]