日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

spring mvc DispatcherServlet详解之前传---前端控制器架构

發布時間:2025/4/5 HTML 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring mvc DispatcherServlet详解之前传---前端控制器架构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

?

?

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

servlet的生命周期

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

Servlet生命周期分為三個階段:【http://www.cnblogs.com/cuiliang/archive/2011/10/21/2220671.html】

  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的初始化

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.*/@Overrideprotected 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.*/@Overrideprotected 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()*/@Overridepublic 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的代碼之美。

轉載于:https://www.cnblogs.com/davidwang456/p/4090058.html

總結

以上是生活随笔為你收集整理的spring mvc DispatcherServlet详解之前传---前端控制器架构的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。