스프링 웹 MVC-04.DispatcherServlet, 스프링 MVC 동작원리
DispatcherServlet 동작 원리 1부
문자열로 리턴, 문자열만 화면 출력 (@ResponseBody를 활용 리턴)
DispatcherServlet 초기화
- 다음의 특별한 타입의 빈들을 찾거나, 기본 전략에 해당하는 빈들을 등록한다.
- HandlerMapping: 핸들러를 찾아주는 인터페이스
- HandlerAdapter: 핸들러를 실행하는 인터페이스
- HandlerExceptionResolver
- ViewResolver
- …
DispatcherServlet 동작 순서
- 요청을 분석한다. (로케일, 테마, 멀티파트 등)
- (핸들러 맵핑에게 위임하여) 요청을 처리할 핸들러를 찾는다.
- (등록되어 있는 핸들러 어댑터 중에) 해당 핸들러를 실행할 수 있는 “핸들러 어댑터”를 찾는다.
- 찾아낸 “핸들러 어댑터”를 사용해서 핸들러의 응답을 처리한다.
- 핸들러의 리턴값을 보고 어떻게 처리할지 판단한다.
- 뷰 이름에 해당하는 뷰를 찾아서 모델 데이터를 랜더링한다.
- @ResponseEntity가 있다면 Converter를 사용해서 응답 본문을 만들고.
- (부가적으로) 예외가 발생했다면, 예외 처리 핸들러에 요청 처리를 위임한다.
- 최종적으로 응답을 보낸다.
HandlerMapping
- RequestMappingHandlerMapping
HandlerAdapter
- RequestMappingHandlerAdapter
DispatcherServlet 동작 원리 2부: SimpleController
뷰가 있는 경우 / 뷰 이름으로 리턴하는 경우
(@ResponseBody를 활용한 리턴이 아닐 경우)
HandlerMapping
- BeanNameUrlHandlerMapping
HandlerAdapter
- SimpleControllerHandlerAdapter
@org.springframework.stereotype.Controller("/simple")
public class SimpleController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return new ModelAndView("/WEB-INF/simple.jsp");
}
}
DispatcherServlet 동작 원리 3부: 커스텀 ViewResolver
ViewResolver
- InternalResourceViewResolver
InternalResourceViewResolver
- Prefix
- Suffix
@Configuration
@ComponentScan
public class WebConfig {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
@org.springframework.stereotype.Controller("/simple")
public class SimpleController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// return new ModelAndView("/WEB-INF/simple.jsp");
return new ModelAndView("simple");
}
}
스프링 MVC 구성 요소
DispatcherSerlvet의 기본 전략 -DispatcherServlet.properties
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
MultipartResolver
- 파일 업로드 요청 처리에 필요한 인터페이스
- HttpServletRequest를 MultipartHttpServletRequest로 변환해주어 요청이 담고 있는 File을 꺼낼 수 있는 API 제공.
LocaleResolver
- 클라이언트의 위치(Locale) 정보를 파악하는 인터페이스
- 기본 전략은 요청의 accept-language를 보고 판단.
ThemeResolver
- 애플리케이션에 설정된 테마를 파악하고 변경할 수 있는 인터페이스
- 참고: https://memorynotfound.com/spring-mvc-theme-switcher-example/
HandlerMapping
- 요청을 처리할 핸들러를 찾는 인터페이스
HandlerAdapter
- HandlerMapping이 찾아낸 “핸들러”를 처리하는 인터페이스
- 스프링 MVC 확장력의 핵심
내가 funtional 하게 구현하고 싶다고 하 인터페이스 만들면 된다. HandlerMapping에서도 어떻게 그 핸들러를 매핑할건지 구현해주면 됨.
HandlerExceptionResolver
- 요청 처리 중에 발생한 에러 처리하는 인터페이스
RequestToViewNameTranslator
- 핸들러에서 뷰 이름을 명시적으로 리턴하지 않은 경우, 요청을 기반으로 뷰 이름을 판단하는 인터페이스
(기본적으로)만약 /simple 요청에서 return null로 하더라도(뷰 네임을 안주더라도), simple이니까 simple이라고 알아서 판단한다.
ViewResolver
- 뷰 이름(string)에 해당하는 뷰를 찾아내는 인터페이스
FlashMapManager
- FlashMap 인스턴스를 가져오고 저장하는 인터페이스
- FlashMap은 주로 리다이렉션을 사용할 때 요청 매개변수를 사용하지 않고 데이터를 전달하고 정리할 때 사용한다.
- redirect:/events
한번 리다이렉트 하고 submit 했을때(post) 두번째는 get 요청만 한다. 두번 submit 방지.
스프링 MVC 동작원리 정리
결국엔 (굉장히 복잡한) 서블릿. = DispatcherServlet
DispatcherServlet 초기화
- 특정 타입에 해당하는 빈을 찾는다.
- 없으면 기본 전략을 사용한다. (DispatcherServlet.properties)
스프링 부트 사용하지 않는 스프링 MVC
- 서블릿 컨네이너(ex, 톰캣)에 등록한 웹 애플리케이션(WAR)에 DispatcherServlet을 등록한다.
- web.xml에 서블릿 등록
- 또는 WebApplicationInitializer에 자바 코드로 서블릿 등록 (스프링 3.1+, 서블릿 3.0+)
- 세부 구성 요소는 빈 설정하기 나름.
스프링 부트를 사용하는 스프링 MVC
- 자바 애플리케이션에 내장 톰캣을 만들고 그 안에 DispatcherServlet을 등록한다.
- 스프링 부트 자동 설정이 자동으로 해줌.
- 스프링 부트의 주관에 따라 여러 인터페이스 구현체를 빈으로 등록한다.
참고로 부트를 사용하면 앞서 설명한 기본 전략(DispatcherServlet.properties)을 사용하는게 아니다.
예를 들면, MultipartResolver 같은 경우 기본 전략에는 없지만, 부트를 사용할 경우 자동으로 넣어준다.
즉, 부트를 사용하면 그냥 파일 업로드 사용 가능하다.
이처럼 좀 더 설정이 자동화 되어 있는 것들이 있다.