环境准备
下图为springMVC接收到http请求时的执行流程图
使用源码:
https://github.com/flowerwind/springMVCDemo
代码解析
在DispatchServlet的doService方法设置断点
DispatchServlet的本质是一个Servlet,Servlet就会运行到其service(HttpServletRequest req, HttpServletResponse resp)方法中,DispatchServlet也不例外。而DispatchServlet的源码中没有service方法,因此会调用其父类FrameworkServlet的service方法,最后调用到其自生的doService方法中,因此说在doService方法上设置断点。doService方法可以作为学习SpringMVC源码的起始点。
继续往下走,发现一直走到doDispatch方处,该方法包含了springMVC分发的主要逻辑。
进入doDispatch往下走,直到this.getHandler方法,该方法接受了request参数,返回了HandlerExecutionChain类型的返回值。对应之前逻辑图中的第二、第三步。
跟进this.getHandler方法,可以看到this.handlerMappings中包含两种handlerMapping,分别是BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping。最后根据配置文件写好的url与控制器、拦截器的映射匹配到一个HandleExecutionChain作为返回值。
接下来获取处理器适配器,对应图中的第四步。
下面看一下获取处理器适配器的代码部分。从动态调试结果可以看到这里有两种适配器,一种是HttpRequestHandlerAdapter,一种是SimpleControllerHandlerAdapter。getHandlerAdapter选取可以处理我们的handler的适配器并返回。
然后一直走到mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这里的ha为之前的处理器适配器,通过处理器适配器调用处理器。
跟入ha.handle方法可以看到其实现。这里由于我的Controller用的是implements Controller的形式,因此处理器适配器为SimpleControllerHandlerAdapter,其handle代码如下,能看到直接就调用了Controller的handleRequest方法。Hello为自己写的控制器,这样就被调用到了,并返回了ModelAndView。
然后代码继续向下走,走到this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException)。
准备进行视图解析,对应流程图中的第八步。跟入processDispatchResult,然后走到this.render(mv, request, response); 这里this.render会做视图解析、渲染视图的工作。
跟入this.render,走到this.resolveViewName,可以看到这里返回了View视图,也就是对应流程图的第八、第九步。
然后通过view.render对视图进行渲染
mv.getModelInternal其实就是返回了model而已,也就是我们在Controller中填充的数据。
因此view.render(mv.getModelInternal(), request, response)就是将我们的数据渲染到视图中。
到此springmvc流程图和源码的对应就搞清了。
后记
几个月前写过DispatchServlet的分析,当时感觉不是很明白,因此重看一边源码,继续学习。