专栏名称: OSC开源社区
OSChina 开源中国 官方微信账号
目录
相关文章推荐
程序员的那些事  ·  重磅!Chrome ... ·  4 天前  
沉默王二  ·  真的建议赶紧搞个软考证书!(红利期) ·  4 天前  
OSC开源社区  ·  PaddleScience——击破科学计算痛 ... ·  5 天前  
51好读  ›  专栏  ›  OSC开源社区

SpringMVC 执行流程及源码解析

OSC开源社区  · 公众号  · 程序员  · 2017-04-15 08:31

正文

请输入标题     bcdef

在SpringMVC中主要是围绕着DispatcherServlet来设计,可以把它当做指挥中心。这里先说明一下SpringMVC文档给出的执行流程,然后是我们稍微具体的执行流程,最后是流程大致的源码跟踪。关于很很很详细的源码解析,这里暂先不做。

请输入标题     abcdefg


官方文档中的流程


首先看下SpringMVC文档上给的流程图:



这张图片给了我们大概的执行流程:


1、用户请求首先发送到前端控制器DispatcherServlet,DispatcherServlet根据请求的信息来决定使用哪个页面控制器Controller(也就是我们通常编写的Controller)来处理该请求。找到控制器之后,DispatcherServlet将请求委托给控制器去处理。


2、接下来页面控制器开始处理用户请求,页面控制器会根据请求信息进行处理,调用业务层等等,处理完成之后,会把结果封装成一个ModelAndView返回给DispatcherServlet。


3、前端控制器DispatcherServlet接到页面控制器的返回结果后,根据返回的视图名选择相应的试图模板,并根据返回的数据进行渲染。


4、最后前端控制器DispatcherServlet将结果返回给用户。


更具体的流程


上面只是总体流程,接下来我们稍微深入一点,看下更具体的流程,这里没有图,只有步骤解析:


1、用户请求发送到前端控制器

DispatcherServlet。


2、前端控制器 DispatcherServlet 接收到请求后,DispatcherServlet 会使用 HandlerMapping 来处理,HandlerMapping 会查找到具体进行处理请求的 Handler 对象。


3、HandlerMapping 找到对应的 Handler 之后,并不是返回一个 Handler 原始对象,而是一个 Handler 执行链,在这个执行链中包括了拦截器和处理请求的 Handler。HandlerMapping 返回一个执行链给 DispatcherServlet。


4、DispatcherServlet 接收到执行链之后,会调用 Handler 适配器去执行Handler。


5、Handler 适配器执行完成 Handler(也就是我们写的 Controller)之后会得到一个 ModelAndView,并返回给 DispatcherServlet。


6、DispatcherServlet 接收到 Handler 适配器返回的 ModelAndView 之后,会根据其中的视图名调用视图解析器。


7、视图解析器根据逻辑视图名解析成一个真正的 View 视图,并返回给 DispatcherServlet。


8、DispatcherServlet 接收到视图之后,会根据上面的 ModelAndView 中的 model 来进行视图中数据的填充,也就是所谓的视图渲染。


9、渲染完成之后,DispatcherServlet 就可以将结果返回给用户了。


源码


DispatcherServlet是一个Servlet,我们知道在Servlet在处理一个请求的时候会交给service方法进行处理,这里也不例外,DispatcherServlet继承了FrameworkServlet,首先进入FrameworkServlet的service方法:



HttpServlet中会根据请求类型的不同分别调用doGet或者doPost等方法,FrameworkServlet中已经重写了这些方法,在这些方法中会调用processRequest进行处理,在processRequest中会调用doService方法,这个doService方法就是在DispatcherServlet中实现的。


下面就看下DispatcherServlet中的doService方法的实现。


请求到达DispatcherServlet


doService方法:



DispatcherServlet开始真正的处理,doDispatch方法:



可以看到大概的步骤还是按照我们上面分析的走的。


查找请求对应的Handler对象


对应着这句代码mappedHandler = getHandler(processedRequest, false);,看下具体的getHandler方法:



继续往下看getHandler:



继续往下看getHandler,在AbstractHandlerMapping类中:



根据requrst获取handler


首先看下根据requrst获取handler步骤getHandlerInternal方法,在AbstractHandlerMethodMapping中:



看下根据路径寻找handler的方法lookupHandlerMethod:



获取默认Handler


如果上面没有获取到Handler,就会获取默认的Handler。如果还获取不到就返回null。


处理String类型的Handler


如果上面处理完的Handler是String类型的,就会根据这个handlerName获取bean。


封装Handler执行链


上面获取完Handler,就开始封装执行链了,就是将我们配置的拦截器加入到执行链中去,getHandlerExecutionChain:



获取对应请求的Handler适配器


getHandlerAdapter:



缓存的处理


也就是对last-modified的处理


执行拦截器的preHandle方法


就是遍历所有的我们定义的interceptor,执行preHandle方法


使用Handler适配器执行当前的Handler


ha.handle执行当前Handler,我们这里使用的是RequestMappingHandlerAdapter,首先会进入AbstractHandlerMethodAdapter的handle方法:



handleInternal方法,在RequestMappingHandlerAdapter中:



组装默认视图名称


前缀和后缀名都加上


执行拦截器的postHandle方法


遍历intercepter的postHandle方法。


处理最后的结果,渲染之类的


processDispatchResult方法:



重点看下render方法,进行渲染:



view.render就是进行视图的渲染,然后跳转页面等处理。


到这里大概的流程就走完了。其中涉及到的东西还有很多,暂先不做详细处理。





推荐阅读

防止网络入侵,这些防火墙工具你一定要知道!

AI 可以自己编程了,程序猿们该何去何从?

2017 年移动应用开发十大趋势

DB-Engines 发布 4 月份全球数据库排名,MySQL 跌幅最大

从代码构建到性能分析,高效 Java 开发人员的首选工具

点击“阅读原文”查看更多精彩内容