spring mvc主流程原始碼閱讀(剖析)
阿新 • • 發佈:2019-06-26
第一步,通過web.xml的配置可以知道,使用者訪問url第一次先走到DispatchServlet,(預設你學過基本的java的Servlet開發)
<servlet> <servlet-name>springServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
DispatchServlet類重點閱讀
//初始化HandlerMap private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { //解析xml的 對映關係後,存放到 handlerMapping 後面會用到 this.handlerMappings = new ArrayList(matchingBeans.values()); OrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException var3) { ; } } if (this.handlerMappings == null) { this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class); if (this.logger.isDebugEnabled()) { this.logger.debug("No HandlerMappings found in servlet '" + this.getServletName() + "': using default"); } } }
下圖為斷點觀察效果
從上圖看到,其實這個map就是從spring-mvc.xml檔案中讀取的不同型別的對映,標準對映、靜態資源、攔截器對映等
//初始化Adapters private void initHandlerAdapters(ApplicationContext context) { this.handlerAdapters = null; if (this.detectAllHandlerAdapters) { Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerAdapters = new ArrayList(matchingBeans.values()); OrderComparator.sort(this.handlerAdapters); } } else { try { HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class); this.handlerAdapters = Collections.singletonList(ha); } catch (NoSuchBeanDefinitionException var3) { ; } } if (this.handlerAdapters == null) { this.handlerAdapters = this.getDefaultStrategies(context, HandlerAdapter.class); if (this.logger.isDebugEnabled()) { this.logger.debug("No HandlerAdapters found in servlet '" + this.getServletName() + "': using default"); } } }
然後,通過斷點+原始碼玩起來了,我這裡是通過一個介面測試的,
首先執行 doService方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (this.logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + requestUri + "]"); } Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { this.logger.debug("Taking snapshot of request attributes before include"); attributesSnapshot = new HashMap(); Enumeration attrNames = request.getAttributeNames(); label113: while(true) { String attrName; do { if (!attrNames.hasMoreElements()) { break label113; } attrName = (String)attrNames.nextElement(); } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource()); FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { this.doDispatch(request, response); } finally { if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { return; } if (attributesSnapshot != null) { this.restoreAttributesAfterInclude(request, attributesSnapshot); } } }
做了一些判斷和資料的初始化工作,這裡不是核心邏輯就暫時跳過了,看
doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null;//關鍵變數,注意觀察 boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this.getHandler(processedRequest, false);//額這裡無語了點了好幾層才找到最終獲取的Handler if (mappedHandler == null || mappedHandler.getHandler() == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());//獲取對應的adaptor String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (this.logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); this.logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//執行方法 } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } this.applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var28) { dispatchException = var28; } this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception var29) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, var29); } catch (Error var30) { this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var30); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } else { if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } } }
獲取handler
handler封裝HandlerExecutionChain,從程式碼來看就是把攔截器相關資訊補充進去
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler); chain.addInterceptors(this.getAdaptedInterceptors()); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); Iterator i$ = this.mappedInterceptors.iterator(); while(i$.hasNext()) { MappedInterceptor mappedInterceptor = (MappedInterceptor)i$.next(); if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain; }
從handlerMap中獲取Adaptors,
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Iterator i$ = this.handlerMappings.iterator(); HandlerExecutionChain handler; do { if (!i$.hasNext()) { return null; } HandlerMapping hm = (HandlerMapping)i$.next(); if (this.logger.isTraceEnabled()) { this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'"); } handler = hm.getHandler(request); } while(handler == null); return handler; }
執行adaptor,最後利用了反射執行代理類的方法
執行後的返回檢視邏輯
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } else { ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); if (!mavContainer.isViewReference()) { mav.setView((View)mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes)model).getFlashAttributes(); HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav; } }
總結:url->dispatchServlet->doService->doDispatch->根據url,從handlerMap獲取handler,然後根據handler獲取adaptor,通過adaptor執行要執行的方法,然後返回頁面或者介面資料(返回的邏輯沒來得及細看)
在這裡即使用到了工廠模式、代理模式