SpringMVC 프로세스 분석
8938 단어 springMVC
SpringMVC 프로세스
서버 시작 단계(DispatcherServlet 초기화 단계)
ContextLoaderListener
은 우선 초기화 방법 contextInitialized(ServletContextEvent event)
에서 initWebApplicationContext(event.getServletContext())
을 호출하여 WebApplicationContext
을 만듭니다.ServletContext
의 속성으로 서브렛 환경에 설정합니다.이 상하문 대상은 상하문 대상이다.ContextLoader#initWebApplicationContext(ServletContext servletContext) servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
DispatcherServlet
초기화 과정에서 WebApplicationContext
대상을 만들고 ContextLoaderListener
이 만든 상하문 대상을 부모 상하문으로 합니다.ServletContext
의 속성으로도 사용됩니다.Framework Servlet#initWebApplicationContext() String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
은 컨텍스트 객체를 작성한 후 onRefresh
을 호출하여 일련의 초기화 작업을 수행합니다.Dispatcher Servlet #initStrategies (Application Context context) initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
이 몇 가지 init 방법의 실현 사고방식은 기본적으로 같다. 먼저 Bean 용기에서 지나간 특정한 유형의 클래스의 실례이다.찾을 수 없으면 기본 설정을 사용합니다.DispatcherServlet.properties
의 구성입니다.DispatcherServlet#initHandlerAdapters(ApplicationContext context) private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
// getHandlerAdapter
OrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
일련의 init 방법을 거친 후
DispatcherServlet
을 정식으로 초기화하여 완성하였다.요청 - 응답 단계
DispatcherServlet
은 표준 Servlet입니다.GET 요청을 보내면 DispatcherServlet
의 doGet(HttpServletRequest request, HttpServletResponse response)
이 처리됩니다.Framework Servlet #doGet(Http Servlet Request request, Http Servlet Response response) processRequest(request, response);
은 processRequest
단계에서 doService
을 주로 호출하고 그 다음에 doDispatch
을 호출합니다.doDispatch
에서 주로 몇 가지 작업이 있습니다.1) 먼저 getHandler
을 호출하여 HandlerMapping
대상을 먼저 얻은 다음에 getHandler
방법으로 HandlerExecutionChain
대상을 되돌려줍니다.구체적으로 HandlerMapping
구현 클래스를 보십시오. 예를 들어 RequestMappingHandlerMapping
Dispatcher Servlet #getHandler(Http Servlet Request request) protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
은 RequestMethodHandlerMapping
을 예로 들 수 있습니다. 이 대상에는 HandlerMethod
의 실례와 이 요청을 처리하는 차단기가 포함되어 있습니다.2) getHandlerAdapter
을 호출하여 첫 번째 supports(handler)
이 true
인 HandlerAdapter
을 얻는다.Dispatcher Servlet #getHandler Adapter(Object handler) protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
3)를 호출한 다음 HandlerExecutionChain#applyPreHandle(...)
을 호출하여 차단기를 적용하고 preHandle
방법을 하나씩 호출합니다.Handler Execution Chain #apply Pre Handle(Http Servlet Request request, Http Servlet Response response) boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
4)에 이어 HandlerAdapter.handle(...)
을 호출하여 ModelAndView
대상을 받았습니다. 그 안에 데이터 대상과 구체적인View 대상이 봉인되어 있습니다.구체적인 실현은 HandlerAdapter
실현류를 살펴야 한다.예: RequestMappingHandlerAdapter
.5) 그리고 HandlerExecutionChain#applyPostHandle(...)
을 호출하여 차단기를 다시 적용하고 postHandle
방법을 호출한다.HandlerExecutionChain #applyPreHandleapplyPostHandle(HttpServletRequest request, HttpServletResponse response, Model AndView mv) void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
6) 마지막 processDispatchResult
처리 결과는 클라이언트에게 상응하는 것입니다.processDispatchResult
에서 render
방법인 Dispatcher Servlet #process Dispatch Result(Http Servlet Request request, Http Servlet Response response, Handler Execution Chain mapped Handler, Model AndView mv, Exception exception) render(mv, request, response);
이 마지막으로 HandlerExecutionChain#triggerAfterCompletion(...)
, 차단기를 호출하는 afterCompletion
방법을 먼저 호출했습니다.차단기 처리 프로세스는 여기서 끝납니다.reader
방법을 분석해 보겠습니다.먼저 resolveViewName
을 호출하고 그 안에서 모든 ViewResolver
의 실례를 훑어보고 resolveViewName
의 방법을 호출하여 첫 번째가 비어 있지 않은 View
의 실례를 되돌려줍니다.DispatcherServlet#resolveViewName(StringviewName, Map model, Localelocale, HttpServletRequest request)protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
ViewResolver#resolveViewName
은 구체적으로 InternalResourceViewResolver
을 참고하여 실현할 수 있다.마지막으로 View
의 render
방법을 호출합니다.render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
방법의 구체적인 실현은 View
실현류 JstlView
을 참고할 수 있다.JstlView
에서 주로 renderMergedOutputModel
을 호출한다. 먼저 모델 대상 데이터를 request
에 설치한 다음에 RequestDispatcher
을 얻어 마지막으로 forward
방법으로 클라이언트에게 응답한다.이로써 요청 - 응답 프로세스가 종료됩니다.
참고 자료
SpringMVC 원본 분석 Spring MVC 강좌, 빠른 입문, 심층 분석 및 SpringMVC 학습
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[Spring MVC] [1] 5. 스프링 MVC - 구조 이해핸들러 조회: 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회 핸들러 어댑터 실행: 핸들러 어댑터를 실행 핸들러 매핑 org.sp...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.