SpringMVC 流程分析
SpringMVC 流程
服務器啟動階段(DispatcherServlet
初始化階段)
-
啟動后
ContextLoaderListener
首先會在初始化方法contextInitialized(ServletContextEvent event)
中調用initWebApplicationContext(event.getServletContext())
來在創建一個WebApplicationContext
。并將其作為ServletContext
的一個屬性設置到Servlet環境中。這個上下文對象為跟上下文對象。
ContextLoader#initWebApplicationContext(ServletContext servletContext)servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
-
DispatcherServlet
初始化過程中中也會創建一個WebApplicationContext
對象,并將ContextLoaderListener
創建的上下文對象作為父上下文。同樣也會將其作為ServletContext
的一個屬性。
FrameworkServlet#initWebApplicationContext()String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac);
創建完上下文對象后還會調用
onRefresh
進行一系列初始化工作。
DispatcherServlet#initStrategies(ApplicationContext 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)
來處理。
FrameworkServlet#doGet(HttpServletRequest request, HttpServletResponse response)processRequest(request, response);
在
processRequest
這一階段主要調用doService
,然后是doDispatch
。 -
處理請求
在doDispatch
主要有一下幾步操作。
1) 首先調用getHandler
首先獲得一個HandlerMapping
對象,然后調用其getHandler
方法返回一個HandlerExecutionChain
對象。具體查看HandlerMapping
實現類,例如RequestMappingHandlerMapping
DispatcherServlet#getHandler(HttpServletRequest 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
。
DispatcherServlet#getHandlerAdapter(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
方法。
HandlerExecutionChain#applyPreHandle(HttpServletRequest request, HttpServletResponse 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, ModelAndView 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
方法
DispatcherServlet#processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception)render(mv, request, response);
最后是
HandlerExecutionChain#triggerAfterCompletion(...)
,調用攔截器的afterCompletion
方法。攔截器處理流程至此結束。
分析一下reader
方法。首先調用resolveViewName
,在里面先遍歷所有的ViewResolver
實例,調用其resolveViewName
方法,返回第一不為空的View
實例。
DispatcherServlet#resolveViewName(String viewName, Map model, Locale locale, 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
,首先Model對象數據放置到request
中,然后得到一個RequestDispatcher
,最后調用其forward
方法響應給客戶端。
至此一個請求-響應過程結束。