-
Spring Web MVC 레퍼런스프로그래밍 2022. 10. 29. 19:40반응형
1. Spring Web MVC
Spring Web MVC는 Servlet API를 기반으로 구축되었다.
1.1 DispatcherServlet
Spring MVC는 DispatcherServlet이라는 중앙 서블릿이 request를 처리하지만, 실제 작업은 대리자에 의해 수행된다.
DispatcherServlet은 다른 서블릿들과 마찬가지로 java configuration이나 web.xml을 통해 선언되고 매핑되어야 한다. 그 다음, DispatcherServlet은 Spring configuration을 이용하여 request 매핑이나 view resolution, 예외 처리를 위한 대리자를 찾는다.
아래 코드는 자바 설정을 등록하고 DispatcherServlet을 초기화하는데, 이는 서블릿 컨테이너에 의해 자동으로 감지된다.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/*"); } }
1.1.1 Context Hierarchy
DispatcherServlet은 자체 설정을 위한 WebApplicationContext를 기대한다.
WebApplicationContext는 ServletContext와 이에 연관된 Servlet에 대한 링크를 가지고 있다.
대부분의 어플리케이션에서 WebApplicationContext 하나면 충분하지만, 한 WebApplicationContext 루트가 여러 DispatcherServlet에 의해 공유될 수도 있다.
루트 WebApplicationContext는 여러 서블릿 인스턴스들에 의해 공유되는 데이터 리포지토리나 비즈니스 서비스들의 빈을 포함하고 있다. 이러한 빈들은 자식 Servlet WebApplicationContext 안에서 상속되고 overridden(재정의됨)된다.public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { App1Config.class }; } @Override protected String[] getServletMappings() { return new String[] { "/app1/*" }; } }
1.1.2 Special Bean Types
DispatcherServlet은 요청 처리와 적절한 반응 렌더링을 위해 특별 빈들을 대리(delegate)한다.
특별 빈에는 HandlerMapping, HandlerAdapter, HandlerExceptionResolver, ViewResolver, LocaleResolver, LocaleContextResolver, ThemeResolver, MultipartResolver, FlashMapManager가 있다.
1.1.3 Web MVC Config
어플리케이션에서 요청 처리를 위한 특별 빈들을 직접 선언할 수도 있다. DIspatcherServlet이 WebApplicationContext를 통해 각 특별 빈들을 체크하고, 만약 선언된 것이 없다면 초기 타입으로 선언한다.
1.1.4 Servlet Config
Servlet 3.0+ 환경에서, 서블릿 컨테이너를 web.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 컨테이너를 초기화하는 인터페이스이다. 이를 구현한 추상 클래스 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[] { "/" }; } }
AbstractDispatcherServletInitializer는 또한 Filter를 추가하는 편리한 방법을 제공하고 자동으로 DispatcherServlet에 매핑한다.public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { // ... @Override protected Filter[] getServletFilters() { return new Filter[] { new HiddenHttpMethodFilter(), new CharacterEncodingFilter() }; } }
1.1.5 Processing
DispatcherServlet은 아래의 방식으로 요청을 처리한다.
- WebApplicationContext는 프로세스 안의 컨트롤러와 다른 요소들이 사용 가능한 attribute로써 바인딩된다.
- locale resolver는 locale을 확인하는 request에 바인딩된다. 만약 locale resolving이 필요하지 않으면 사용하지 않을 수 있다.
- theme resolver는 뷰에 어떤 테마를 사용할지에 대한 요청에 바인딩된다. 만약 필요하지 않으면 무시할 수 있다.
- multipart file resolver를 등록한다면 요청은 멀티파트를 사용하는지 검사된다. 만약 멀티파트가 발견되면 요청은 MultipartHttpServletRequest에 의해 wrap된다.
- 적절한 핸들러를 검색한다. 만약 핸들러가 발견되면, 핸들러와 관련된 실행 체인이 렌더링을 위한 모델을 실행한다. 대안으로, 어노테이션 컨트롤러에는 response가 view를 리턴하는 것 대신에 렌더링된다.
- 만약 model이 리턴되면, 뷰가 렌더링된다. 만약 리턴된 모델이 없다면 어떠한 뷰도 렌더링되지 않는다.
WebApplicationContext 안에 선언된 HandlerExceptionResolver 빈은 요청 처리 도중 던져진 예외를 처리하기 위해 사용된다. 이러한 예외 리졸버는 커스터마이징할 수 있다.
HTTP 캐싱 지원을 위해, 핸들러는 checkNotModified 메소드나 WebRequest를 사용할 수 있다.
개별 DispatcherServlet 인스턴스들은 서블릿 초기화 파라미터를 추가함으로써 커스터마이징할 수 있다.
1.1.6 Path Matching
Servlet API는 전체 요청 경로를 RequestURI로 표시하고, contextPath, servletPath, pathInfo로 세분화한다. 각각의 값들은 서블릿이 매핑된 방식에 따라 다르다. Spring MVC는 contextPath와 servletMapping prefix를 제외한 DispatcherServlet 안의 경로를 결정해야 한다.
1.1.7 Interception
모든 HandlerMapping 구현체들은 특정 요청에 특정 기능을 적용할 때 유용한 핸들러 인터셉터를 제공한다. 인터셉터들은 반드시 HandlerInterceptor 안의 세가지 메소드를 구현해야 한다.
- preHandle(..) : 핸들러가 실행되기 전
- postHandle(..) : 핸들러가 실행되고 난 후
- afterCompletion : 요청이 완료되고 난 후
preHandle(..) 메소드는 불리언 값을 리턴한다. 우리는 이 메소드를 사용하여 실행 체인의 처리를 계속하거나 멈출수 있다. 이 메소드가 true를 리턴할때, 핸들러 실행 체인이 계속된다. false를 리턴할때, DIspatcherServlet은 인터셉트 자신이 리퀘스트를 처리하고, 다른 인터셉터들과 실제 핸들러를 계속하지 않는다고 가정한다.
1.1.8 Exceptions
만약 요청 매핑 중에 예외가 발생하거나 요청 핸들러로부터 예외가 던져진다면, DispatcherServlet은 HandlerExceptionResolver 빈의 체인을 대리하여 대안 핸들링을 제공한다.
1.1.9 View Resolution
1.1.10 Locale
1.1.11 Themes
1.1.12 Multipart Resolver
1.1.13 Logging반응형'프로그래밍' 카테고리의 다른 글
[Spring Boot] CORS 문제 (0) 2023.05.21 자바 서블릿 (Java Servlet) 정리 (0) 2022.10.31 스프링 시큐리티 레퍼런스 (0) 2022.10.24 8. 블로그 프로젝트 (0) 2022.07.28 7. 블로그 프로젝트 (0) 2022.07.27