您好,登錄后才能下訂單哦!
本篇內容介紹了“Java源碼分析SpringMVC執行流程”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
先看一下SpringMVC執行流程再看源碼,有助理解:
?戶發送請求?前端控制器DispatcherServlet。
DispatcherServlet 收到請求調? HandlerMapping 處理器映射器。
處理器映射器找到具體的處理器(可以根據xml配置、注解進?查找),?成處理器及處理器攔截器(如果有則?成)?并返回給DispatcherServlet。
DispatcherServlet調?HandlerAdapter處理器適配器。
HandlerAdapter經過適配調?具體的處理器(Controller,也叫后端控制器)
Controller執?完成返回ModelAndView。
HandlerAdapter 將 Controller 執?結果 ModelAndView 返回給DispatcherServlet。
DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器。
ViewReslover解析后返回具體View。
DispatcherServlet根據View進?渲染視圖(即將模型數據填充?視圖中)。
DispatcherServlet 響應?戶。
我們都知道當從用戶發起請求到后端是,首先走的就是DispatcherServlet,接著就會調用doService()
方法執行業務邏輯,doService()
方法也只是一個中轉站,實際執行邏輯的是doDispatch()
方法,且看源碼:
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); // 省略部分源碼 try { // 執行實際邏輯 doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); } }
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 { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 為當前請求獲取映射處理器 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 獲取映射處理器適配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 實際調用的Handler mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } //處理轉發結果 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
下面來看一下其中幾個重要的方法:
1.getHandler(HttpServletRequest request)方法:該方法是處理當前請求找到合適的HandlerMapping,并返回一個HandlerExecutionChain,HandlerExecutionChain,HandlerExecutionChain包含了具體的處理器(handler)和攔截器列表。
HandlerMapping 默認的實現有org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
和 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
。
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
2.getHandlerAdapter(Object handler) 根據HandlerExecutionChain中的handler來獲取處理器適配器(HandlerAdapter),
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
HandlerAdapter有兩個默認實現類,分別是 org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
和 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
,前者用于沒有使用模板引擎的請求,后者用于使用了模板引擎的接口。
實際處理請求的是HandlerAdapter的handle方法,如果是沒有使用例如JSP等的模板引擎,handle方法就會返回null,如果使用了模板引擎就會返回一個ModelAndView對象。
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
handle方法最終調用的是Controller接口的 handleRequest(HttpServletRequest request, HttpServletResponse response)
方法來處理請求。
以SimpleControllerHandlerAdapter#handle方法源碼為例:
@Override @Nullable public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); }
3.processDispatchResult方法用于處理轉發結果,該結果要么是一個ModelAndView,要么拋異常。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); //處理異常 mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { //加載視圖 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. mappedHandler.triggerAfterCompletion(request, response, null); } }
processDispatchResult
方法中在正常情況下會調用render
方法。
4.render方法用來通過名稱呈現視圖,它也是請求處理的最后一步。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null) { // 通過視圖名稱獲取視圖 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + getServletName() + "'"); } } // Delegate to the View object for rendering. if (logger.isTraceEnabled()) { logger.trace("Rendering view [" + view + "] "); } try { if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } //渲染視圖 view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "]", ex); } throw ex; } }
DispatcherServlet的render
方法是對視圖View的封裝,最后調用的還是View的render方法。
resolveViewName
方法用于解析視圖名稱,它會通過視圖解析器ViewResolver的resolveViewName
方法解析視圖并返回一個視圖View,然后再通過View的render方法渲染視圖,至于是怎么渲染視圖的這里就不介紹了,感興趣的可以自行查看源碼。
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }
“Java源碼分析SpringMVC執行流程”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。