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=

这个就是咱们页面上的内容了。

相关文章
相关标签/搜索