ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [2-ch5 스프링 MVC 패턴] 기본구조와 로딩구조 (DispatcherServlet, listener, ViewResolver)
    Back-End/Spring Legacy 2022. 8. 15. 11:30

     

    스프링 웹 프로젝트를 진행하려면 제일 중요하게 알아야되는 기본 개념이 바로 MVC 패턴의 구조이다. 국비 수업을 들으면서 몇번이고 반복해서 학습했더니 조금씩 눈에 들어오는 느낌? 처음엔 이게 무슨 소리야,, 헷갈리는 부분도 많았지만 전체적인 기본구조와 로딩구조를 정리하면서 디자인 패턴이나 xml의 역할 등 세세하게 알아볼까한다. 

     

     

    스프링 MVC 프로젝트 내부 구조

     

    스프링 MVC 프로젝트를 구성해서 사용한다는 의미는 내부적으로 root-context.xml로 사용하는 일반 Java 영역 (흔히 POJO)과 servlet-context.xml로 설정하는 Web 관련 영역을 같이 연동해서 구동하게 된다. 

     

     

     

    위의 틀을 WebApplicationContext라고 볼 수 있는데, 이 존재는 기존의 구조에 MVC 설정을 포함하는 구조로 만들어진다. 스프링은 원래 목적 자체가 웹 애플리케이션을 목적으로 나온 프레임워크가 아니기 때문에 달라지는 영역에 대해서는 완전히 분리하고 연동하는 방식으로 구현돼 있다. 

     

     

     

    스프링 로딩 구조

     

    Spring Legacy프로젝트 중 MVC Project를 생성하고 실행해보면 로그가 기록되는 걸 확인할 수 있다. 이 로그를 이용해 어떤 과정을 통해서 프로젝트가 실행되는지 알 수 있다. 프로젝트 구동 시 관려하는 xml은 web.xml, roo-context.xml, servlet-context.xml이다. 이 중 web.xml은 Tomcat 구동 ( 즉 서블릿)과 관련된 설정이고, 나머지 두 파일은 스프링과 관련된 설정이다. 

     

     

     

    < web.xml >

     

    web.xml 상단에는 가장먼저 구동되는 Context Listener가 등록되어 있다. 

     

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

     

     

     

    <context-param>에서는 root-context.xml의 경로가 설정되어 있고, <listener>에는 스프링 MVC의 ContextLoaderListener가 등록되어 있는 것을 볼 수 있다. ContextLoaderListener는 해당 웹 애플리케이션 구동 시 같이 동작하므로 프로젝트 실행 시 가장 먼저 로그를 출력하면서 기록되는 걸 볼 수 있다. 

     

     

     

     

     

     

    root-context.xml이 처리되면 파일에 있는 빈(Bean) 설정들이 동작하게 된다. root-context.xml에 정의된 객체(Bean)들은 스프링 영역(context) 안에 생성되고, 객체들 간의 의존성이 처리된다. root-context.xml이 처리된 후에는 스프링 MVC에서 사용하는 DispatcherServlet이라는 서블릿과 관련된 설정이 동작한다. 

     

     

     

    <!-- 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>
    
    </web-app>

     

     

     

    DispatcherServlet 클래스는 스프링 MVC의 구조에서 가장 핵심적인 역할을 하는 클래스이다. 이에 관한 설명은 아래 동작 과정에서 추가적으로 설명할 예정. 내부적으로 웹 관련 처리의 준비작업을 진행하는데 이때 사용하는 파일이 servlet-context.xml이다.  DispatcherServlet에서 XmlWebApplicationContext를 이용해서 servlet-context.xml을 로딩하고 해석하기 시작한다. 이 과정에서 등록된 객체들을 기존에 만들어진 객체들과 같이 연동하게 된다. 

     

     

     

     

    모델 2와 스프링 MVC

     

     

    스프링 MVC는 내부적으로는 Servlet API를 활용한다. 스프링 MVC는 '모델2'라는 방식으로 처리되는 구조이므로 모델 2 방식에 대해 살펴볼 필요가 있다. 모델2 방식은 쉽게 말해 '로직과 화면을 분리' 하는 스타일의 개발 방식이다. 

     

     

     

     

    모델 2방식에서 사용자의 Request는 특별한 상황이 아닌 이상 먼저 Controller를 호출한다. 이렇게 설계하는 가장 중요한 이유는 나중에 View를 교체하더라도 사용자가 호출하는 url 자체에 변화가 없게 만들어주기 때문이다. 컨트롤러는 데이터를 처리하는 존재를 이용해 데이터(Model)을 처리하고 Response할 때 필요한 데이터(Model)를 View 쪽으로 전달하게 된다. (여기서 3번째 순수한 데이터 처리 로직은 root-content.xml을 의미한다. )

     

     


     

     

     

    그렇다면 스프링 MVC의 구조는 어떨까? 아래 그림을 먼저 살펴보자.

     

     

     

     

     

    1. 사용자의 Request는 Front-Controller인 DispatcherServlet을 통해 처리한다. 아래 web.xml을 보면 모든 Request를 DispatcherServlet이 받도록 처리하고 있다. 

     

     

     

     

    2 & 3. HandlerMapping은 Request의 처리를 담당하는 컨트롤러를 찾기 위해 존재한다. HandlerMapping 인터페이스를 구현한 여러 객체들 중 RequestMappinrgHandlerMap-ping 같은 경우는 개발자가 @RequestMapping어노테이션이 적용된 것을 기준으로 판단하게 된다. 적절한 컨트롤러를 찾았다면 HandlerAdapter를 이용해 해당 컨트롤러를 동작시킨다. 즉) HandlerAdapter는 해당하는 Controller 중 요청한 URL에 맞는 적합한 Method를 찾아준다. 

     

     

    4. Controller는 개발자가 작성하는 클래스로 실제 Request를 처리하는 로직을 작성하게 된다. ( 즉, Business Logic을 처리하는 것인데 이에 Service -> Repository -> Database 순으로 호출해서 원하는 데이터를 받아오는 것! ) 이때 View에 전달해야 하는 데이터는 주로 Model이라는 객체에 담아서 전달한다. Controller는 다양한 타입의 결과를 반환하는데 이에 대한 처리는 View Resolver를 이용하게 된다. 

     

     

    5. ViewResolver는 Controller가 반환결과를 어떤 View를 통해서 처리하는 것이 좋은지 해석하는 역할이다. 가장 흔하게 사용되는 설정읜 servlet-context.xml에 정의된 InternalResourceViewResolver이다. 

     

    	<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>
    	
    	<context:component-scan base-package="org.zerock.controller" />

     

     

    6 & 7. View는 실제로 응답 보내야 하는 데이터를 jsp 등을 이용해 생성하는 역할을 하게 된다. 만들어진 응답은 DispatcherServlet을 통해 전송된다. 즉 DispatcherServlet은 view 객체에 처리 결과를 넘겨 최종 결과를 보여주는 것, View는 Model 객체에서 화면 표시에 필요한 객체를 가져와 화면 표시를 처리하고 client에게 넘겨준다. 

     

     

     


     

    Spring 실행 순서

     

     

     

     

     

    위에서 정리한 MVC 패턴 기본 구조에 덧붙여 Spring 실행 순서에 대해 더 자세히 알아보겠다. 

     

    1. 웹 애플리에이션 즉) Tomcat을 실행시키면 web.xml이 Loading된다. 

     

     

    2. web.xml에 등록되어 있는 ContextLoaderListener (Java Class) 생성되는데 서플릿 컨테이너가 파일을 읽어서 구성될 때 ContextLoaderListener 가 자동으로 메모리에 생성되는 것.  ContextLoaderListener  클래스는 ServletContextListener 인터페이스를 구현하고 있으며, ApplicationContext를 생성하는 역할을 수행한다. ContextLoaderListener  는 서블릿의 생명 주기를 관리해준다. 한마디로 말해서 서블릿을 사용하는 시점에서 서블릿 컨텍스트를 ApplicationContext 등록, 서블릿이 종료되면 ApplicationContext  삭제. 

     

     

    3. 생성된 ContextLoaderListener 는 datasource인 root-context.xml을 Loading한다. 이동할 파일은 web.xml에 param으로 설정해서 사용한다. 

     

     

     

    4. root-context.xml에 있는 Spring Container (Service)가 구동된다. root-context.xml에는 주로 view 지원을 제한 공통 bean을 설정한다. 

     

    5. 클라이언트로부터 웹 어플리케이션 요청이 온다. 최초의 DispatcherServlet 생성 

     

    6. DispatcherServlet이 생성된다. DispatcherServlet은 HandlerMapping을 통해 컨트롤러를 호출해 요청을 처리하고 servlet-context.xml 파일을 로딩해 보내온 view 이름을 토대로 처리 view를 검색한다. 

     

     

     

    반응형

    댓글

Designed by Tistory.