国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開發(fā) > Java > 正文

spring mvc DispatcherServlet之前端控制器架構(gòu)詳解

2024-07-14 08:40:21
字體:
供稿:網(wǎng)友

前端控制器是整個(gè)MVC框架中最為核心的一塊,它主要用來攔截符合要求的外部請(qǐng)求,并把請(qǐng)求分發(fā)到不同的控制器去處理,根據(jù)控制器處理后的結(jié)果,生成相應(yīng)的響應(yīng)發(fā)送到客戶端。前端控制器既可以使用Filter實(shí)現(xiàn)(Struts2采用這種方式),也可以使用Servlet來實(shí)現(xiàn)(spring MVC框架)。

spring,mvc,DispatcherServlet,控制器

DispatcherServlet 作為前置控制器是web服務(wù)器的入口,是spring mvc最重要的一個(gè)類,通過它的生命周期可以加深對(duì)web服務(wù)器的理解。

servlet的生命周期

首先我們回憶一下servlet的生命周期:

Servlet生命周期分為三個(gè)階段:【Servlet生命周期與工作原理詳解】

  1.初始化階段  調(diào)用init()方法。Servlet被裝載后,Servlet容器創(chuàng)建一個(gè)Servlet實(shí)例并且調(diào)用Servlet的init()方法進(jìn)行初始化。在Servlet的整個(gè)生命周期內(nèi),init()方法只被調(diào)用一次。

  2.響應(yīng)客戶請(qǐng)求階段  調(diào)用service()方法

  3.終止階段  調(diào)用destroy()方法

Servlet初始化階段

  在下列時(shí)刻Servlet容器裝載Servlet:

  1.Servlet容器啟動(dòng)時(shí)自動(dòng)裝載某些Servlet,實(shí)現(xiàn)它只需要在web.XML文件中的<Servlet></Servlet>之間添加如下代碼:  

<loadon-startup>1</loadon-startup>
  2.在Servlet容器啟動(dòng)后,客戶首次向Servlet發(fā)送請(qǐng)求

  3.Servlet類文件被更新后,重新裝載Servlet

DispatcherServlet的結(jié)構(gòu)

復(fù)習(xí)了上述知識(shí)后我們來看看DispatcherServlet的結(jié)構(gòu):

DispatcherServlet繼承自抽象類:FrameworkServlet,間接繼承了HttpServlet (FrameworkServlet繼承自HttpServletBean,而HttpServletBean繼承自HttpServlet )

Servlet的初始化

spring,mvc,DispatcherServlet,控制器

 protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); //文件上傳解析,如果請(qǐng)求類型是multipart將通過MultipartResolver進(jìn)行文件上傳解析; initLocaleResolver(context); //本地化解析 initThemeResolver(context);   //主題解析 initHandlerMappings(context); //通過HandlerMapping,將請(qǐng)求映射到處理器 initHandlerAdapters(context); //通過HandlerAdapter支持多種類型的處理器 initHandlerExceptionResolvers(context); //如果執(zhí)行過程中遇到異常將交給HandlerExceptionResolver來解析 initRequestToViewNameTranslator(context); //直接解析請(qǐng)求到視圖名 initViewResolvers(context); //通過ViewResolver解析邏輯視圖名到具體視圖實(shí)現(xiàn) initFlashMapManager(context); //flash映射管理器 }

servlet如何處理請(qǐng)求:

servlet的service方法處理http請(qǐng)求。

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請(qǐng)求類型有七種(外加一個(gè)option選項(xiàng)),定義如下:

public enum RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE}

FrameworkServlet的service()處理不同的請(qǐng)求,我們以常見的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 抽象定義了處理流程,留待子類來實(shí)現(xiàn)該方法,完成具體的請(qǐng)求處理。

/** * 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;

具體實(shí)現(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);  } } }

重頭戲,作為請(qǐng)求分發(fā)器的實(shí)現(xiàn):

功能:1. 把請(qǐng)求分發(fā)到handler(按照配置順序獲取servlet的映射關(guān)系獲取handler);2. 根據(jù)servlet已安裝的  HandlerAdapters 去查詢第一個(gè)能處理的handler;3. handler激發(fā)處理請(qǐng)求

 /** * 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é):

本文因篇章限制,僅僅介紹了請(qǐng)求處理的流程,沒有對(duì)代碼進(jìn)行深入的分析,接下來的文章將從細(xì)微處著手,分析spring的代碼之美。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到JAVA教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 璧山县| 云和县| 阳曲县| 全州县| 永清县| 安义县| 陆丰市| 合川市| 睢宁县| 中宁县| 张掖市| 巴彦淖尔市| 芦山县| 航空| 文昌市| 新闻| 瑞丽市| 夏津县| 游戏| 江都市| 新干县| 平谷区| 木兰县| 繁昌县| 乐昌市| 彭阳县| 前郭尔| 启东市| 安康市| 红原县| 太保市| 永和县| 伊通| 建瓯市| 德化县| 宜兴市| 新丰县| 潍坊市| 靖江市| 洪雅县| 杭锦后旗|