SpringMvc請求處理流程與源碼探祕

流程梳理

dispatcherServlet做爲前端控制器的主要做用就是接受請求與處理響應。前端

不過它不是傳統意義上的servlet,它在接受到請求後採用轉發的方式,將具體工做交給專業人士去作。json

參與角色主要有:mvc

  • 前端控制器(DispatcherServlet)app

  • 處理映射器(HandlerMapping)jsp

  • 處理適配器(HandlerAdapter)async

  • 處理器((Handler)Controller)ide

  • 視圖解析器(ViewReslover)ui

  • 視圖(View)this

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

(找了一張圖,把請求過程與步驟清晰的呈現了出來)url

 

第一步:前端控制器dispatcher接受請求

  • Client---url--->Dispatcher

第二步:前端控制器去發起handler映射查找請求

  • Dispatcher---HttpServletRequest---> HandlerMapping

第三步:處理器映射器查找hanlder並返回HandlerExetuionChain

  • Dispatcher <---HandlerExeutionChain---HandlerMapping

第四步:前端控制器發起請求處理器適配器請求執行

  • Dispatcher---Handler---> HandlerAdapter

第五步:處理器適配器去調用handler執行

  • HandlerAdapter---HttpServletRequest> Handler(Controller)

第六步:處理器處理後返回ModelAndView給HandlerAdapter

  • HandlerAdapter <---ModelAndView---Handler(Controller)

第七步:處理器適配器將ModelAndView返回給前端控制器

  • Dispatcher <---ModelAndView---HandlerAdapter

第八步:前端控制器請求視圖解析器解析ModelAndView

  • Dispatcher---ModelAndView---> ViewReslover

第九步:視圖解析器解析視圖後返回視圖View給前端控制器

  • Dispatcher <---View---ViewReslover

第十步:前端控制器請求視圖要求渲染視圖

  • Dispatcher--->View--->render

第十一步:前端控制器返回響應

  • Response <---Dispatcher

 

源碼探祕

第一步接受請求:

咱們能夠來看看DispatcherServlet的繼承結構

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

其實DispatcherServlet能處理請求是由於HttpServlet類的service方法,而HttpServlet又來自Servlet接口定義的規範。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

能夠看到抽象類HttpServlet實現了接口Servlet的service方法,根據請求類型不一樣執行了不一樣的方法(doGet,doPost)

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

當請進來後,由HttpServlet的子類FrameworkServlet重寫的service方法執行請求,能夠看到437行子類調用了父類的service方法,而後在父類執行doGet之類的方法時,因爲子類FrameworkServlet重寫了父類方法,交由子類執行,因此進到了個人doGet斷點裏面,它調用了處理請求方法。

接下來咱們看看Proce***equest方法的源碼

 1 protected final void proce***equest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2        long startTime = System.currentTimeMillis();
 3        Throwable failureCause = null;
 4        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
 5        LocaleContext localeContext = this.buildLocaleContext(request);
 6        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
 7        ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
 8        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 9        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor(null));
10        this.initContextHolders(request, localeContext, requestAttributes);
11
12        try {
13            this.doService(request, response);
14        } catch (IOException | ServletException var16) {
15            failureCause = var16;
16            throw var16;
17        } catch (Throwable var17) {
18            failureCause = var17;
19            throw new NestedServletException("Request processing failed", var17);
20        } finally {
21            this.resetContextHolders(request, previousLocaleContext, previousAttributes);
22            if (requestAttributes != null) {
23                requestAttributes.requestCompleted();
24            }
25
26            this.logResult(request, response, (Throwable)failureCause, asyncManager);
27            this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
28        }
29
30    }

 

前面一系列初始化工做咱們先無論,看看重要的部分,try裏面的doService方法

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

跟蹤進去看了一下,因爲它是抽象方法,因此會由子類實現和執行,也就是咱們的DispatchServlet類了

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 1protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
 2        this.logRequest(request);
 3        Map

 

因此第一步也就完成了,第一步的任務就是走進這裏來。

第二步:前端控制器去發起handler映射查找請求

Dispatcher---HttpServletRequest---> HandlerMapping

上面的源碼中主要工做就是給request實例設置一系列參數,要注意的就是doDispatch方法,這裏面就是mvc的核心了,前面第一張交互圖裏面的流程都是在這裏實現的。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

能夠看到,經過HttpRequestServlet做爲參數請求handlerMapping

第三步:處理器映射器查找hanlder並返回HandlerExetuionChain

Dispatcher <---HandlerExeutionChain---HandlerMapping

能夠看到上圖中返回了mappedHandler變量,就是HandlerExtuceChain類型

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

能夠看到,已經找到並返回了咱們的HomeController處理器(Hanlder)

第四步:前端控制器發起請求處理器適配器請求執行

 Dispatcher---Handler---> HandlerAdapter

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

從508行能夠看到,適配器傳入handler對象和reaquest等信息,執行handler()方法

第五步:處理器適配器去調用handler執行

HandlerAdapter---HttpServletRequest> Handler(Controller)

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

從這裏能夠看到,調用的handlerInternal是個抽象方法,會調用子類的實現方法,子類由RequestMappingHandlerAdapter實現,這個類也是咱們常常在xml裏面配置的類

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

經過invokeHandlerMethod方法執行進到controller裏面

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

方法執行後返回咱們的index

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

第六步:處理器處理後返回ModelAndView給HandlerAdapter

HandlerAdapter <---ModelAndView---Handler(Controller)

經過調用invokeHandlerMethod方法返回ModelAndView

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

第七步:處理器適配器將ModelAndView返回給前端控制器

Dispatcher <---ModelAndView---HandlerAdapter

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

第八步:前端控制器請求視圖解析器解析ModelAndView

Dispatcher---ModelAndView---> ViewReslover

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

第九步:視圖解析器解析視圖後返回視圖View給前端控制器

Dispatcher <---View---ViewReslover

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

能夠看到,返回的視圖,url指向index.jsp頁面

第十步:前端控制器請求視圖要求渲染視圖

Dispatcher--->View--->render

若是View對象不爲空,將會調用render方法渲染

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

若是返回的是json對象,屬於接口的,是不會走這裏的

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

此時會找對應的視圖解析器去渲染

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

裏面其實也沒幹啥,就作了個跳轉,到jsp頁面去綁定數據

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

第十一步:前端控制器返回響應

Response <---Dispatcher

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

到這裏也就基本上完了。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

處理請求完成後作了個重置工做,而後發佈一個事件,你能夠選擇監聽這個事件,作相應處理。

再看看response裏面

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

這個就是咱們頁面上的內容了。

相關文章
相關標籤/搜索