前端控制器是整個MVC框架中最為核心的一塊,它主要用來攔截符合要求的外部請求,并把請求分發(fā)到不同的控制器去處理,根據(jù)控制器處理后的結(jié)果,生成相應(yīng)的響應(yīng)發(fā)送到客戶端。前端控制器既可以使用Filter實現(xiàn)(Struts2采用這種方式),也可以使用Servlet來實現(xiàn)(spring MVC框架)。
十多年的大方網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。成都營銷網(wǎng)站建設(shè)的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整大方建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。成都創(chuàng)新互聯(lián)從事“大方網(wǎng)站設(shè)計”,“大方網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。
DispatcherServlet 作為前置控制器是web服務(wù)器的入口,是spring mvc最重要的一個類,通過它的生命周期可以加深對web服務(wù)器的理解。
servlet的生命周期
首先我們回憶一下servlet的生命周期:
Servlet生命周期分為三個階段:【Servlet生命周期與工作原理詳解】
1.初始化階段 調(diào)用init()方法。Servlet被裝載后,Servlet容器創(chuàng)建一個Servlet實例并且調(diào)用Servlet的init()方法進(jìn)行初始化。在Servlet的整個生命周期內(nèi),init()方法只被調(diào)用一次。
2.響應(yīng)客戶請求階段 調(diào)用service()方法
3.終止階段 調(diào)用destroy()方法
Servlet初始化階段
在下列時刻Servlet容器裝載Servlet:
1.Servlet容器啟動時自動裝載某些Servlet,實現(xiàn)它只需要在web.XML文件中的<Servlet></Servlet>之間添加如下代碼:
<loadon-startup>1</loadon-startup>
2.在Servlet容器啟動后,客戶首次向Servlet發(fā)送請求
3.Servlet類文件被更新后,重新裝載Servlet
DispatcherServlet的結(jié)構(gòu)
復(fù)習(xí)了上述知識后我們來看看DispatcherServlet的結(jié)構(gòu):
DispatcherServlet繼承自抽象類:FrameworkServlet,間接繼承了HttpServlet (FrameworkServlet繼承自HttpServletBean,而HttpServletBean繼承自HttpServlet )
Servlet的初始化
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); //文件上傳解析,如果請求類型是multipart將通過MultipartResolver進(jìn)行文件上傳解析; initLocaleResolver(context); //本地化解析 initThemeResolver(context); //主題解析 initHandlerMappings(context); //通過HandlerMapping,將請求映射到處理器 initHandlerAdapters(context); //通過HandlerAdapter支持多種類型的處理器 initHandlerExceptionResolvers(context); //如果執(zhí)行過程中遇到異常將交給HandlerExceptionResolver來解析 initRequestToViewNameTranslator(context); //直接解析請求到視圖名 initViewResolvers(context); //通過ViewResolver解析邏輯視圖名到具體視圖實現(xiàn) initFlashMapManager(context); //flash映射管理器 }
servlet如何處理請求:
servlet的service方法處理http請求。
FrameworkServlet.java 定義了servlet的service和destroy方法,如下所示:
/** * Override the parent class implementation in order to intercept PATCH * requests. */ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getMethod(); if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) { processRequest(request, response); } else { super.service(request, response); } }
我們知道http請求類型有七種(外加一個option選項),定義如下:
public enum RequestMethod { GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE }
FrameworkServlet的service()處理不同的請求,我們以常見的post來說明:
/** * Process this request, publishing an event regardless of the outcome. * <p>The actual event handling is performed by the abstract * {@link #doService} template method. */ protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try { doService(request, response); } catch (ServletException ex) { failureCause = ex; throw ex; } catch (IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } if (logger.isDebugEnabled()) { if (failureCause != null) { this.logger.debug("Could not complete request", failureCause); } else { if (asyncManager.isConcurrentHandlingStarted()) { logger.debug("Leaving response open for concurrent processing"); } else { this.logger.debug("Successfully completed request"); } } } publishRequestHandledEvent(request, startTime, failureCause); } }
FrameworkServlet 抽象定義了處理流程,留待子類來實現(xiàn)該方法,完成具體的請求處理。
/** * Subclasses must implement this method to do the work of request handling, * receiving a centralized callback for GET, POST, PUT and DELETE. * <p>The contract is essentially the same as that for the commonly overridden * {@code doGet} or {@code doPost} methods of HttpServlet. * <p>This class intercepts calls to ensure that exception handling and * event publication takes place. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure * @see javax.servlet.http.HttpServlet#doGet * @see javax.servlet.http.HttpServlet#doPost */ protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;
具體實現(xiàn)如下:
/** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<String, Object>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, 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 { doDispatch(request, response); } finally { if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { return; } // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } }
重頭戲,作為請求分發(fā)器的實現(xiàn):
功能:1. 把請求分發(fā)到handler(按照配置順序獲取servlet的映射關(guān)系獲取handler);2. 根據(jù)servlet已安裝的 HandlerAdapters 去查詢第一個能處理的handler;3. handler激發(fā)處理請求
/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ 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); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. 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 (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
servlet銷毀
/** * Close the WebApplicationContext of this servlet. * @see org.springframework.context.ConfigurableApplicationContext#close() */ @Override public void destroy() { getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'"); // Only call close() on WebApplicationContext if locally managed... if (this.webApplicationContext instanceof ConfigurableApplicationContext && !this.webApplicationContextInjected) { ((ConfigurableApplicationContext) this.webApplicationContext).close(); } }
小結(jié):
本文因篇章限制,僅僅介紹了請求處理的流程,沒有對代碼進(jìn)行深入的分析,接下來的文章將從細(xì)微處著手,分析spring的代碼之美。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
網(wǎng)頁題目:springmvcDispatcherServlet之前端控制器架構(gòu)詳解
URL網(wǎng)址:http://m.newbst.com/article32/jeiesc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、企業(yè)建站、動態(tài)網(wǎng)站、手機(jī)網(wǎng)站建設(shè)、網(wǎng)站排名、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)