亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

spring mvc DispatcherServlet之前端控制器架構詳解

2024-07-14 08:40:21
字體:
來源:轉載
供稿:網友

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

spring,mvc,DispatcherServlet,控制器

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

servlet的生命周期

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

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

  1.初始化階段  調用init()方法。Servlet被裝載后,Servlet容器創建一個Servlet實例并且調用Servlet的init()方法進行初始化。在Servlet的整個生命周期內,init()方法只被調用一次。

  2.響應客戶請求階段  調用service()方法

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

Servlet初始化階段

  在下列時刻Servlet容器裝載Servlet:

  1.Servlet容器啟動時自動裝載某些Servlet,實現它只需要在web.XML文件中的<Servlet></Servlet>之間添加如下代碼:  

<loadon-startup>1</loadon-startup>
  2.在Servlet容器啟動后,客戶首次向Servlet發送請求

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

DispatcherServlet的結構

復習了上述知識后我們來看看DispatcherServlet的結構:

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

Servlet的初始化

spring,mvc,DispatcherServlet,控制器

 protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); //文件上傳解析,如果請求類型是multipart將通過MultipartResolver進行文件上傳解析; initLocaleResolver(context); //本地化解析 initThemeResolver(context);   //主題解析 initHandlerMappings(context); //通過HandlerMapping,將請求映射到處理器 initHandlerAdapters(context); //通過HandlerAdapter支持多種類型的處理器 initHandlerExceptionResolvers(context); //如果執行過程中遇到異常將交給HandlerExceptionResolver來解析 initRequestToViewNameTranslator(context); //直接解析請求到視圖名 initViewResolvers(context); //通過ViewResolver解析邏輯視圖名到具體視圖實現 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 抽象定義了處理流程,留待子類來實現該方法,完成具體的請求處理。

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

具體實現如下:

 

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

重頭戲,作為請求分發器的實現:

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

 /** * 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(); } }

小結:

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产成人精品午夜| 国产精品中文字幕久久久| 久久久欧美精品| 一本色道久久综合狠狠躁篇的优点| 在线成人激情视频| 国产日韩精品入口| 97精品国产91久久久久久| 日韩免费在线看| 成人淫片在线看| 亚洲精品自拍第一页| 日韩中文第一页| 欧美性xxxxxxxxx| 日韩欧美综合在线视频| 久久这里有精品视频| 国产精品激情av在线播放| 在线精品视频视频中文字幕| 日韩精品中文字幕在线播放| 国产精品欧美亚洲777777| 国产精品露脸自拍| www.美女亚洲精品| 精品福利视频导航| 国产欧美日韩精品在线观看| 亚洲欧洲自拍偷拍| 中文字幕日韩有码| 国产精品欧美激情| 日韩成人av在线| 欧美富婆性猛交| 久久天天躁狠狠躁夜夜躁2014| 国产丝袜一区二区三区| 亚洲精品大尺度| 久久久久久成人精品| 亚洲国产日韩欧美在线动漫| 欧美日韩在线看| 亚洲片国产一区一级在线观看| 亚洲欧美www| 超薄丝袜一区二区| 一区二区三区国产在线观看| 成人a免费视频| 日本久久亚洲电影| 精品福利一区二区| 欧美性猛交xxxx免费看| 日韩电影免费观看在线观看| 精品国产区一区二区三区在线观看| 欧美理论在线观看| 久久精品久久久久久| 九九九久久久久久| 69久久夜色精品国产69乱青草| 91精品国产色综合久久不卡98口| 久久久999国产| 日韩中文字幕第一页| 国色天香2019中文字幕在线观看| 91在线精品播放| 日韩av一区在线| 久久久天堂国产精品女人| 欧美黑人极品猛少妇色xxxxx| 欧美体内谢she精2性欧美| 黑人欧美xxxx| 国产亚洲美女精品久久久| 久久久久久com| 欧美精品电影免费在线观看| 欧美午夜激情视频| 精品视频在线播放色网色视频| 国产精品自产拍在线观看中文| 668精品在线视频| 亚洲a∨日韩av高清在线观看| 91精品国产自产在线观看永久| 欧美日韩久久久久| 黑人精品xxx一区一二区| 久久天天躁日日躁| 亚洲欧洲国产精品| 精品电影在线观看| 色小说视频一区| 久久精品成人欧美大片| 少妇久久久久久| 亚洲人高潮女人毛茸茸| 亚洲专区国产精品| 国产精品美女免费| www.99久久热国产日韩欧美.com| 久久久99免费视频| 岛国av一区二区在线在线观看| 欧美精品18videosex性欧美| 亚洲天堂成人在线| 国产日本欧美一区二区三区在线| 69视频在线免费观看| 日韩激情视频在线| 亚洲一区二区三区777| 中文字幕视频一区二区在线有码| 国产主播在线一区| 欧美精品九九久久| 高清欧美性猛交xxxx黑人猛交| 亚洲v日韩v综合v精品v| 欧美激情一二三| 亚洲精品国产综合区久久久久久久| 97久久精品视频| 欧美色播在线播放| 欧美成人全部免费| 精品欧美激情精品一区| 国外日韩电影在线观看| 91国产高清在线| 国产精品久久久久久久久久ktv| 日韩成人在线观看| 国内精品久久久久影院优| 国内精品模特av私拍在线观看| 日韩免费av片在线观看| 亚洲欧美精品一区二区| 欧美性xxxxx| 91精品啪aⅴ在线观看国产| 这里只有精品在线观看| 日韩av一卡二卡| 亚洲精品国产免费| 久久久久久久久久国产| 激情成人中文字幕| 亚洲精品一区二区三区婷婷月| 精品福利视频导航| 精品国内亚洲在观看18黄| 黄色精品一区二区| 国产精品女人网站| 精品视频在线播放| 国产精品偷伦视频免费观看国产| 精品国产视频在线| 欧美丰满少妇xxxxx| 日韩色av导航| 在线观看日韩av| 中文字幕亚洲一区| 日韩av片免费在线观看| 欧美日本亚洲视频| 亚洲aaaaaa| 日韩高清电影免费观看完整版| 国产一区二区三区视频免费| 亚洲欧美一区二区三区情侣bbw| 日本一区二区在线免费播放| 国产精品9999| 78m国产成人精品视频| 亚洲欧美日本另类| 成人美女av在线直播| 国产精品a久久久久久| 亚洲女人被黑人巨大进入| 亚洲人成77777在线观看网| 久久综合色影院| 色一情一乱一区二区| 啪一啪鲁一鲁2019在线视频| 精品国产鲁一鲁一区二区张丽| 日韩av黄色在线观看| 欧美激情视频播放| 热久久99这里有精品| 欧美在线视频观看| 国产成人拍精品视频午夜网站| 久久久久久久久久久av| 久久国产天堂福利天堂| 国产激情久久久久| 97香蕉久久超级碰碰高清版| 国产精品亚洲综合天堂夜夜| 亚洲国产精品电影在线观看| 久久精品国产免费观看| 成人性生交大片免费看小说| 精品福利在线看| 一区二区三区久久精品| 亚洲桃花岛网站| 高跟丝袜一区二区三区| 午夜精品一区二区三区在线视| 久久久久久91| 日韩高清中文字幕| 中文字幕日韩电影| 久久国产精品影视|