개발영어공부

[Spring 공식문서 번역 프로젝트] Spring Web MVC (~1.1.4)

robinjoon98 2022. 4. 7. 10:52

이 포스트는 https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc 의 번역입니다. 영어 공부가 목적이고, 따라서 오역, 의역이 있을 수 있습니다.

 

Web on Servlet Stack ( 서블렛 기반의 웹)

버전 5.3.18

이 문서는 Servlet API기반으로 구축되어 Servlet 컨테이너 에서 동작하는 Servlet 기반의 웹 어플리케이션을 만드는 것을 다룹니다. 세부 챕터들은 Spring MVC, View Technologies, CORS Support, 그리고 WebSocket Support을 포함합니다. 반응형 기반의 웹 어플리케이션에 대한 문서는 Web on Reactive Stack을 참고하세요.

1. Spring Web MVC

Spring Web MVC는  Servlet API 를 기반으로 구축된 독자적인 프레임워크이며 처음부터 Spring 프레임워크에 포함되어있었습니다. 공식적인 이름은 Spring Web MVC 이지만 일반적으로 Spring MVC 로 불립니다.

 

Spring Web MVC와 더불어 Spring 5.0에서 반응형스택 웹 프레임워크인 Spring WebFlux 를 소개했습니다. 이 문서는 Spring Web MVC를 다룹니다. 

 

Servlet 컨테이너와 Java EE 버전의 기준정보와 호환되는 범위는 Spring 프레임워크 위키 문서를 참고하세요.

1.1 DispatcherServlet

Spring MVC 는 다른 많은 프레임워크들 처럼 Front Controller 패턴을 사용해 설계되었습니다. 중앙 Servlet인 DispatcherServlet은 요청 처리를 위한 공통된 알고리즘을 제공하고, 실제 작업은 다른 컴포넌트에게 위임하는 구조입니다. 이런 구조는 유연하고 다양한 실행흐름을 지원합니다.

 

다른 Servlet과 마찬가지로 DispatcherServlet은 Servlet 사양에 따라 Java 설정 방식이나 web.xml을 이용해 선언되고 매핑되어야 합니다. 그 다음에 DispatcherServlet은 요청매핑, View, 예외처리 등의 작업을 위임할 컴포넌트를 Spring 설정을 통해 검색합니다. 

 

아래 예제 코드는 DispatcherServlet을 등록하고 초기화하는 Java 코드이다. 이 코드는 스프링 컨테이너에 의해 자동으로 탐지되어 실행됩니다. 1.4 장을 참고하세요.

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class);

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}
ServletContext API를 직접 사용하는것 외에도 AbstractAnnotationConfigDispatcherServletInitializer 를 확장하고 몇개의 메서드를 오버라이딩 할 수 도 있습니다. (1.1.1 Context Hierarchy에 예시가있습니다.)

 

For programmatic use cases, a GenericWebApplicationContext can be used as an alternative to AnnotationConfigWebApplicationContext. See the GenericWebApplicationContext javadoc for details.

아래는 web.xml 을 이용해 DispatcherServlet을 등록하고 초기화하는 예시입니다.

<web-app>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

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

    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>

</web-app>
스프링 부트는 다른 초기화과정을 따릅니다. 서블릿 컨테이너의 라이프사이클을 후킹하는 것 보단 스프링 부트는 스프링 설정을 이용해 자기 자신과 내장된 서블릿 컨테이너를 시동시킵니다. Filter와 Servlet 은 스프링 설정에서 감지되고 서블릿 컨테이너와 함께 등록됩니다. 더 자세한 사항은 스프링 부트 문서를 참고하세요.
1.1.1.Context Hierarchy

DispatcherServlet은 자체 구성을 ApplicationContext의 확장인 WebApplicationContext에 기대합니다.(의역 필요한데 뭐라 해야 할지 모르겠음. 원문 : DispatcherServlet expects a WebApplicationContext (an extension of a plain ApplicationContext) for its own configuration.) WebApplicationContext은 ServletContext와 이에 연결된 Servlet의 참조를 가지고 있습니다.

1.1.2. Special Bean Types

DispatcherServlet은 요청처리와 적절한 응답을 만드는 작업을 "Special Beans"에게 위임한다. "Special Beans" 는 Spring 프레임워크 계약을 구현하는 스프링관리 객체를 의미합니다. 이들은 보통 프레임워크에서 기본으로 제공하는 것을 사용하지만, 사용자가 이들의 속성을 커스터마이징 하거나 확장, 대체할 수 있습니다.

 

아래 표는 DispatcherServlet에 의해 탐지되는 special bean의 목록입니다.

Bean typeExplanation

Bean  종류 설명
HandlerMapping 전처리와 후처리를 하는 interceptors 목록과 함께 요청을 처리기에 매핑합니다. 매핑은 몇개의 기준을 따르며, 상세한 것은 HandlerMapping 구현체에 따라 달라집니다.
RequestMappingHandlerMapping ,SimpleUrlHandlerMapping 이 대표적인 HandlerMapping의 구현체입니다. RequestMappingHandlerMapping 은 @RequestMapping 어노테이션을 지원하고, SimpleUrlHandlerMapping 은 핸들러에 대한 URI 경로패턴의 명시적 등록을 유지합니다.
원문 : SimpleUrlHandlerMapping (which maintains explicit registrations of URI path patterns to handlers).
HandlerAdapter 핸들러가 실제로 어떻게 호출되는지에 상관없이 DispatcherServlet이 요청에 대응되는 핸들러를 호출하게 도와준다. 즉, 일종의 어뎁터 패턴으로서, DispatcherServlet이 각종 세부사항을 무시할 수 있도록 해주는 것이 HandlerAdapter이다.
HandlerExceptionResolver 예외를 처리하기 위한 전략으로 가능하면 예외를 핸들러에 대응시킨다. 자세한 것은 예외 참조
ViewResolver 핸들러에서 반환된 String 기반의 응답이름을 실제 view 로 바꾸는 작업을 한다.
자세한 것은 View Resolution 과 View Technologies.을 참조.
LocaleResolver, LocaleContextResolver 시간대를 처리한다.  Locale. 참조
ThemeResolver Resolve themes your web application can use — for example, to offer personalized layouts. See Themes.
MultipartResolver 브라우저에서의 파일 업로드 와 같은 multi-part 요청을 처리한다. MultiPart Resolver 참조
FlashMapManager Store and retrieve the “input” and the “output” FlashMap that can be used to pass attributes from one request to another, usually across a redirect. See Flash Attributes.

1.1.3. Web MVC Config

애플리케이션은 요청을 처리하는 데 필요한 특수한 빈 타입(1.1.2에 나열된)의 인프라 빈 리스트를 선언할 수 있다.DispatcherServlet 은 각각의 speacil bean의 WebApplicationContext을 체크한다. 만약, 일치하는 타입의 빈이 없다면, DispatcherServlet.properties에 쓰여있는 기본 타입으로 돌아간다.

 

대부분의 경우  MVC Config(1.11)이 최고의 시작점이다. 이것은 Java 또는 xml로 필요한 빈을 정의하고 커스터마이징하는 보다 높은 수준의 콜백 API를 제공합니다. 

Spring Boot는 MVC Java 구성에 의존하여 Spring MVC를 구성하고 많은 추가 편리한 옵션을 제공합니다.

1.1.4. Servlet Config

Servlet 3.0 이상에서는 Servlet 컨테이너 설정을 프로그래밍 방식으로 구성하는 것과, xml로 구성하는 두가지 옵션이 있습니다. 아래는 DispatcherServlet 을 등록하는 예시입니다.

import org.springframework.web.WebApplicationInitializer;

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        XmlWebApplicationContext appContext = new XmlWebApplicationContext();
        appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext));
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

WebApplicationInitializer 는 Spring MVC에서 개발자의 구현이 어떤 Servlet 3 컨테이너에서도 자동으로 탐지되고 적용되도록 보장하기 위해 제공하는 인터페이스 입니다. WebApplicationInitializer 를 구현한 추상클래스인 AbstractDispatcherServletInitializer 는 서블릿 매핑과  DispatcherServlet 구성의 위치를 ​​지정하는 메소드 오버라이딩을 통해 DispatcherServlet 등록하는 것을 더 쉽게 해줍니다.

 

아래는 자바 기반의 스프링 설정을 하는 애플리케이션을 위한 예제 코드 입니다.

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { MyWebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

만약, XML 기반의 스프링 설정을 한다면 아래와같이  AbstractDispatcherServletInitializer 을 직접 상속해야 한다.

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        XmlWebApplicationContext cxt = new XmlWebApplicationContext();
        cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
        return cxt;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

AbstractDispatcherServletInitializer 은 Filter를 추가하고, 자동으로  DispatcherServlet와 매핑하는 편리한 방법도 제공한다. 아래의 예시코드를 따라해보라.

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

    // ...

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] {
            new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
    }
}

각각의 필터는 필터의 구체적인 타입에 따라 정해지는 기본 이름으로 추가되며 자동으로 DispatcherServlet와 매핑된다.

AbstractDispatcherServletInitializer 의 protected 메서드인 isAsyncSupportedDispatcherServlet과 이에 매핑된 모든 필터를 비동기적으로 사용할 수 있게 해주는 하나의 공간을 제공한다. 기본적으로 이것은 활성화되어있다.

마지막으로, 만약 DispatcherServlet 자체를 커스터마이징해야 한다면, createDispatcherServlet 메서드를 오버라이딩 하면 된다.