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方法響應給客戶端。
至此一個請求-響應過程結束。