1. 程式人生 > >SpringMVC的流程分析(一)—— 整體流程概括

SpringMVC的流程分析(一)—— 整體流程概括

classes amp 不同 方法 restfu equals 類圖 strong .get

SpringMVC的整體概括

之前也寫過springmvc的流程分析,只是當時理解的還不透徹所以那篇文章就放棄了,現在比之前好了些,想著寫下來分享下,也能增強記憶,也希望可以幫助到別人,如果文章中有什麽錯誤的地方歡迎各位指出。(本文針對有一定的springmvc使用經驗的it人員)。

1.springmvc存在的意義

  任何一個框架都有其存在的價值,可以或多或少幫助我們解決一個繁瑣的問題,springmvc也不例外,說白了其實他也沒啥了不起,他就是個徹頭徹尾的Servlet,

一個封裝許多任務的servlet,正是這些封裝我們才感覺不到他單單是個servlet,因為他太厲害了,每個人在使用的時候應該都有過配置web.xml的經驗,其中可以清晰的看到springmvc的配置,如下:

 <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/classes/spring/spring-servlet.xml</
param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

  我們可以看到springmvc的配置就是一個servlet的配置,對所有的url進行攔截。所以我們可以總結springmvc的作用:作為一個總的servlet對客戶端的請求進行分發,然後對不同的請求處理,並返回相應的數據。

2.springmvc的設計類圖

技術分享

3.springmvc的入口

  上圖中黃色標識的DispatcherServlet就是sprigmvc請求的核心入口類,可以看到這類通過FrameworkServelt間接繼承了HttpServletBean,FrameworkServelt實現了ApplicationContextAware,用來設置springmvc的全局上下文,當客戶發送請求時會先進入DispatcherServlet的doService方法:

  

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  
       //省略不重要代碼。。。
        try {
            this.doDispatch(request, response);
        } finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot1);
            }
        }

    }

  其實是調用了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 {
            try {
                ModelAndView err = null;
                Exception dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ex.getLastModified(request, mappedHandler.getHandler());
                        if (this.logger.isDebugEnabled()) {
                            this.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;
                    }

                    err = ex.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(request, err);
                    mappedHandler.applyPostHandle(processedRequest, response, err);
                } catch (Exception arg18) {
                    dispatchException = arg18;
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);
            } catch (Exception arg19) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, arg19);
            } catch (Error arg20) {
                this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, arg20);
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }
       
        }
    }

首先一上來是檢查是否是文件上傳請求,(這個檢查的目的是為了在finally中清除文件上傳相應的信息),然後就是獲取handler

  mappedHandler = this.getHandler(processedRequest);

  什麽是handler呢?其實handler是springmvc自己定義的一個處理具體請求的不同類的總稱,我們知道客戶端的請求有很多類型,例如靜態資源的請求,動態資源的請求,restful風格的請求,也可能有原始servlet類型的請求,這些處理類的總稱就是handler,具體如何得到handler我會另起一個章節講解。好了,得到了hander(處理請求類)後我們是不是可以直接來處理請求了呢,就像這樣:
  handler.methodname(request,response);
其實還真是這樣,哈哈,肯定是這樣的呀,不過人家springmvc的設計者比咱們高明多了,才不會這麽lou的寫,好了,我們看看他們是怎麽高明的吧:

  HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());

  HandlerAdapter?這是什麽鬼呀,怎麽得到了handler怎麽還在得到HandlerAdapter呢,其實這就是人家的高明之處了,這裏使用了適配器設計模式,每一種handler都會有一個對應的適配器,這樣子我們就不用每次都判斷handler的類型,然後調用不同的方法了,舉個例子:

class Handler1{
  Object handle1(HttpRequest request,HttpResponse response){
    
  }
}
class Handler2{
  Object handle2(HttpRequest request,HttpResponse response){
    
  }
}
class Handler3{
  Object handle3(HttpRequest request,HttpResponse response){
    
  }
}

這裏有3個處理類,正常我們的調用是這樣的:  

if (handle instanceof Handler1) {
  handle.handle1();
}
if (handle instanceof Handler2) {
  handle.handle2();
}
if (handle instanceof Handler3) {
  handle.handle3();
}

  如果我們此時又多了一個Handler4怎麽辦,難道們需要更改Springmvc的源代碼嗎,這顯然不符合代碼設計的開閉原則,適配器模式就是解決這個問題的最好方式每一個處理器都要有一個對應的適配器,這樣我們就可以不用更改源代碼也能添加handler了。
  接下來我們看到

 err = ex.handle(processedRequest, response, mappedHandler.getHandler());

  這個方法是請求的最終執行,不同類型的handler會有不同的實現,當處理器處理完各自的邏輯後都會放回一個ModelAndView參數,ModelAndView是springmvc對處理器返回的結果的抽象,不論處理器實際返回的是什麽,Springmvc都會講他包裝成為ModelAndView,然後對ModelAndView進行處理,這裏很有意思,也給我們一種啟發,如果我們會得到很多不同的結果,我們可以將它抽象為一個統一的類型數據,然後針對這個類型的數據進行統一的處理,這樣我們就可以不用針對每種情況後處理了。
  最後,Spingmvc會對ModelAndView進行處理,然後返回給瀏覽器。

 this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);

上面這個方法就是對ModelAndView的處理。至此,springmvc的大體流程就結束了。以上只是我對springmvc的一個整體概述,之後我還會講解Springmvc的Handler,HandlerAdapter,視圖處理,攔截器,異常處理等內容。









SpringMVC的流程分析(一)—— 整體流程概括