Keep going

스프링 MVC의 기본 구조 본문

Records/Spring Framework

스프링 MVC의 기본 구조

코딩천재홍 2021. 2. 5. 15:42

- 스프링은 하나의 기능을 위해서 만들어진 프레임워크가 아니라 '코어'라고 할 수 있는 프레임워크에 여러 서브 프로젝트를 결함해서 다양한 상황에 대처할 수 있도록 개발되었다. 

- 서브 프로젝트라는 의미는 별도의 설정이 존재할 수 있다라는 개념이다.

- Spring Legacy Project 로 생성한 프로젝트도 servlet-context.xml 과 root-context.xml로 설정 파일이 분리된 것을 볼 수 있다.

- 스프링 MVC 가 서브 프로젝트이므로 구성 방식이나 설정 역시 조금 다르다고 볼 수 있다.

 

[출처] https://elevatingcodingclub.tistory.com/34


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

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

 

[출처] https://elevatingcodingclub.tistory.com/34

- 바깥쪽에 있는 WebApplicationContext라는 존재는 기존의 구조에 MVC 설정을 포함하는 구조로 만들어진다.

- 스프링은 원래 목적 자체가 웹 애플리케이션을 목적으로 나온 프레임워크가 아니기 때문에 달라지는 영역에 대해서는 완전히 분리하고 연동하는 방식으로 구현되어 있다.

 

# porm.xml 설정

<properties>
    <java-version>1.8</java-version>
    <org.springframework-version>5.0.7.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
cs

 

<!-- Lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.18</version>
    <scope>provided</scope>
</dependency>
cs

 

<!-- Spring-test -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
cs

 

<!-- Servlet -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>
cs

 

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.5.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerArgument>-Xlint:all</compilerArgument>
        <showWarnings>true</showWarnings>
        <showDeprecation>true</showDeprecation>
    </configuration>
</plugin>
cs

 

 

- 웹 프로젝트는 가능하면 절대 경로를 이용하는 구조를 사용하는 것이 바람직하다.

- Tomcat의 'Modules' 메뉴를 이용해서 '/' 경로로 프로젝트가 실행될 수 있도록 처리한다.

 

 

실행 결과

 

 

 

# Java 설정을 이용하는 경우

 

- java 설정을 이용하는 프로젝트는 web.xml , servlet-context.xml , root-context.xml 을 제거하고,

porm.xml에서 web.xml이 없다는 설정을 추가해야 한다.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.2.0</version>
    <configuration>
     <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>
 
cs

 

- xml 파일을 삭제했으므로 새로운 패키지를 생성하고 WebConfig클래스와 RootConfig 클래스를 작성한다.

 

// RootConfig
package
 org.zerock.config;
 
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class RootConfig {
 
}
 
cs

 

// ServletConfig
package org.zerock.config;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
 
@EnableWebMvc
@ComponentScan(basePackages = {"org.zerock.controller"})
public class ServletConfig implements WebMvcConfigurer {
    
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
    
    InternalResourceViewResolver bean = new InternalResourceViewResolver();
    bean.setViewClass(JstlView.class);
    bean.setPrefix("/WEB-INF/views/");
    bean.setSuffix(".jsp");
    registry.viewResolver(bean);
    
    }
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
 
}
 
cs

- ServletConfig 클래스는 기존의 servlet-context.xml에 설정된 모든 내용을 담아야 한다. 

1. 주로 @EnableWebMvc 어노테이션과 WebMvcConfigurer 인터페이스를 구현하는 방식을 사용한다.

2. 일반 @Configuration 우선 순위가 구분되지 않는 경우에,  @Configuration과 WebMvcConfigurationSupport 클래스를 상속하는 방식도 사용한다.

 

- WebMvcConfigurere는 스프링 MVC와 관련된 설정을 메서드로 오버라이드 하는 형태를 이용할 때 사용한다.

- ServletConfig 클래스 역시 @ComponentScan을 이용해서 다른 패키지에 작성된 스프링의 객체를 인식할 수 있다.

 

//WebConfig
package org.zerock.config;
 
import org.springframework.web.servlet.support.
AbstractAnnotationConfigDispatcherServletInitializer;
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
 
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] {RootConfig.class};
    }
 
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] {ServletConfig.class};
    }
 
    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
 
}
 
cs

- 작성된 ServletConfig 클래스를 정상적으로 실행하려면 WebConfig의 위와 같이 ServletConfig를 이용하고, 스프링의 MVC의 기본경로도 '/'로 변경해야한다.

 

 

실행 결과

 


프로젝트의 로딩 구조

- 프로젝트가 정상적으로 실행되었다면 서버의 구동 시 약간의 로그가 기록되는 것을 볼 수 있다.

- 프로젝트 구동 시 관여하는 XML은 web.xml, root-context.xml, servlet-context.xml 파일이다. 

  이 파일들 중 web.xml은 Tomcat 구동과 관련된 설정이고, 나머지 두 파일은 스프링과 관련된 설정이다.

 

- 프로젝트의 구동은 web.xml에서 시작한다. web.xml의 상단에는 가장 먼저 구동되는 Context Listener가 등록되어 있다.

 

web.xml 일부

- <context-param>에는 root-context.xml의 경로가 설정되어 있고 <listener> 에는 스프링 MVC의 ContextLoaderListener가 등록되어 있는 것을 볼 수 있다.

- ContextLoaderListener는 해당 웹 애플리케이션 구동 시 같이 동작하므로 프로젝트를 실행하면 가장 먼저 로그를 출력하면서 기록한다.

- root-context.xml이 처리되면 파일에 있는 빈 설정들이 동작하게 된다.

 

[출처] https://elevatingcodingclub.tistory.com/34

- root-context.xml에 정의된 객체들은 스프링의 영역안에 생성되고, 객체들 간의 의존성이 처리된다.

- root-context.xml이 처리된 후에는 스프링 MVC에서 사용하는 DispatcherServlet이라는 서블릿과 관련된 설정이 동작한다.

 

 

 

web.xml 일부

- org.springframework.web.servlet.DispatherServlet 클래스는 스프링 MVC의 구조에서 가장 핵심적인 역할을 하는 클래스이다.

- 내부적으로 웹 관련 처리의 준비작업을 진행하는데 이때 사용하는 파일이 servlet-context.xml이다.

 

[출처] https://elevatingcodingclub.tistory.com/34

- DispatcherServlet에서 XmlWebApplicationContext를 이용해서 servlet-context.xml을 로딩하고 해석하기 시작하는데 이 과정에서 등록된 객체(Bean) 들은 기존에 만들어진 객체들과 연동되게 됩니다.

 


스프링 MVC의 기본 사상

 

[출처] https://elevatingcodingclub.tistory.com/34

- Servlet/JSP에서는 HttpServletRequest / HttpServletResponse라는 타입의 객체를 이용해 브라우저에서 전송한 정보를 처리하는 방식을 사용한다. 스프링 MVC의 경우 이 위에 하나의 계층을 더한 형태가 된다.

 

- 스프링 MVC를 이용하게 되면 개발자들은 직접적으로 HttpServletRequest/HttpServletResponse 등과 같이 Servlet/JSP의 API를 사용할 필요성이 현저하게 줄어든다.

- 스프링은 중간에 연결 역할을 하기 때문에 이러한 코드를 작성하지 않고도 원하는 기능을 구현할 수 있게 해준다.

 

- 개발자의 코드는 스프링 MVC에서 동작하기 때문에 과거에는 스프링 MVC의 특정한 클래스를 상속하거나 인터페이스를 구현하는 형태로 개발할 수 있었지만, 스프링 2.5버젼부터 등장한 어노테이션 방식으로 인해 최근 개발에는 어노테이션이나 XML 등의 설정만으로 개발이 가능하게 되었다.

 


모델 2와 스프링 MVC

- 스프링 MVC는 내부적으로 Servlet API를 활용하는데, '모델2' 방식으로 처리된다.

- 모델2 방식은 '로직과 화면을 분리'하는 스타일의 개발 방식이다.

 

- 사용자는 Request는 특별한 상황이 아닌 이상 먼저 Controller를 호출하게 된다. (나중에 view를 교체하더라도 사용자가 호출하는 URL 자체에 변화가 없게 만들어주기 때문)

- 컨트롤러는 데이터를 처리하는 존재를 이용해서 데이터를 처리하고 Response 할 때 필요한 데이터(Model)를 View 쪽으로 전달하게 된다.

- Servlet을 이용하는 경우 개발자들은 Servlet API의 RequestDisaptcher 등을 이용해서 이를 직접 처리해 왔지만 스프링 MVC는 내부에서 이러한 처리를 하고, 개발자들은 스프링 MVC API 를 이용해서 코드를 작성하게 된다.

 

 

스프링 MVC의 기본 구조

사용자의 Request는 Front-controller 인 DispathcerServlet을 통해서 처리한다. 생성된 프로젝트의 web.xml을 보면 아래와 같이 모든 Request를 DispatcherServlet이 받도록 처리하고 있다.

 

②, ③ HandlerMapping은 Request의 처리를 담당하는 컨트롤러를 찾기 위해서 존재한다.

HandlerMapping 인터페이스를 구현한 여러 객체들 중 RequestMappingHandlerMapping 는 개발자가 @RequestMapping 어노테이션이 적용된 것을 기준으로 판단하게 된다.

적절한 컨트롤러가 찾아졌다면 HandlerAdapter를 이용해서 해당 컨트롤러를 동작시킨다.

 

Controller는 개발자가 작성하는 클래스로 실제 Request를 처리하는 로직을 작성하게 된다. 이때 View에 전달해야 하는 데이터는 주로  Model이라는 객체에 담아서 전달한다. Controller는 다양한 타입의 결과를 반환하는데 이에 대한 처리는 ViewResolver를 이용하게 된다.

 

ViewResolverController가 반환한 결과를 어떤 View를 통해서 처리하는 것이 좋을지 해석하는 역할이다.

가장 흔하게 사용하는 설정은 servlet-context.xml에 정의된 InternalResourceViewResolver이다.

 

⑥, ⑦ View실제로 응답 보내야 하는 데이터를 Jsp등을 이용해서 생성하는 역할을 하게 된다. 

만들어진 응답은 DispatcherServlet을 통해서 전송한다.

 

 

- 모든 Request는 DispatcherServlet을 통하도록 설계되었는데, 이런 방식을 Front-Controller 패턴이라고 한다.

 

- Front-Controller 패턴을 이용하면 전체 흐름을 강제로 제한할 수 있다. 예를 들어 HttpServlet을 상속해서 만든 클래스를 이용하는 경우 특정 개발자는 이를 활용할 수 있지만 다른 개발자는 자신이 원래 하던 방식대로 HttpServlet을 그대로 상속해서 개발할 수도 있다.

 

- Front-Controller 패턴을 이용하는 경우에는 모든 Request의 처리에 대한 분배가 정해진 방식대로만 동작하기 때문에 좀 더 엄격한 구조를 만들어 낼 수 있다.

 

 


출처 : 코드로 배우는 스프링 웹 프로젝트 [구멍가게 코딩단]

'Records > Spring Framework' 카테고리의 다른 글

스프링 MVC 의 Controller(2)  (0) 2021.02.09
스프링 MVC의 Controller  (0) 2021.02.08
MyBatis와 스프링 연동  (0) 2021.02.03
스프링과 Oracle Database 연동  (0) 2021.02.03
의존성 주입 테스트(생성자 이용)  (0) 2021.02.03
Comments