一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
目录
SpringMvc源码探秘(一)Tomcat启动项目时Spring做了什么
SpringMvc源码探秘(二)DispatchServlet初始化
前言
在上一篇文章中,我们讲到了DispatchServlet在init时做了哪些操作,这里先简单总结下。
- 创建WebApplicationContext
- 执行applicationContext的Refresh方法
- 执行DispatchServlet中的init开头的方法 包含但不限于以下方法。
- initHandlerMappings
- initHandlerAdapters
- initViewResolvers
- ....
正式开始
首先我们先回忆下web.xml的配置。 可以看下框出来的配置信息,大家应该都知道意思,url/开头的请求都进入DispatchServlet当中去。
所以这里要想一下Servlet的生命周期。
init方法初始化 -> service方法处理请求 -> doGet/doPost方法
也就是说,在浏览器上输入一个地址,会先进入service方法处理,根据请求方式判断,进入不同的请求方式处理方法。我这里发起一个简单的Get请求。
然后按照生命周期的标准去寻找doGet方法,但是我在DispatchServlet中并没有找到对应的方法,所以这个时候去看他的父类。 通过查看,所有的请求方法都指向一个processRequest方法,追进去看一下。
processRequest
方法刚开始,注册了一些参数,基本都是上面声明,下面方法就用到了,我们不去细扣方法里面的细节。
catch里面的抛错误的我们就不看了,看到try里面一个doService方法,看样子是执行代码关键方法。随后值得注意的是在finally的最后的一行代码。广播一个RequestHandled事件,这里请求处理应该结束了,所以推送一个事件我们进去简单看一下。 推送的是一个ServletRequestHandledEvent,看这里这个样子应该可以用来做个简单请求日志记录,等文章结尾时,写一个事件监听器看一下。
doService 方法
这是一个抽象方法,我们直接看DispatchServlet中的实现即可。
方法一进入,打印了一个日志这里不用看。
随后映入眼帘的就是一个If判断。判断条件也很简单,就是request当中有没有IncludeRequest这个属性,很明显,我们并没有设置这个属性,所以不用管他。返回的是False。
就算进入的话,看这个样子,就是向attributesSnapshot里面put一些数据,只不过这里我不知道put的是什么数据,无关紧要看下一段代码。
这里向request的属性中添加几个值,applicationContext、localeResolver、themeResolver、themeSource,第一个可以理解,其他的没见过也没用过,等遇到了再看是干嘛的,这里记住request中已经有几个属性就行了。
这一段代码和上一段代码同理,也是像request对象中放入属性,这里记住有这几个属性就行。
这一段代码没看懂是干嘛的,给外面声明的变量赋了个值,跳过吧,后面用到再说。
这是最后一段代码,try中里面一个doDispatch方法,和调用doService方法时一样,看来这是关键代码,下面的finally操作,就不看了没有什么具体的意义。
doDispatch方法
方法刚开始声明了一些变量,瞄一眼有个印象即可,下方代码中大概率还会用到赋值什么的。
这里主要看后面两个方法。checkMultipart方法看字面意思是检查是否Multipart,也就是是否是文件上传的Request,随后把这个里面返回的值赋值给了刚开头创建processRequest。也就是说这个里面可能会返回一个新的Request对象,跟进去简单扫一眼。 果然,这里和我想的一样,如果请求是multipart的话,会重新创建一个Request返回出来,这样也就解释的通,最后那行代码为什么是ProcessedRequest != request了。
此处代码根据Request获取了Handler,需要追进去看一下代码。
getHandler
这个获取当前类下所有的HandlerMappings,通过Debug得知有两个。 看这里很容易可以看出来,我们需要调用的是RequestMappingHandler中的方法,接下来定位到这个类。
看一下RequestMappingHandlerMapping的一个类关系图,简单记一下后面有用。 这个方法是在AbstractHandlerMapping类中的,我们直接追进去查看。
看到上述代码,即可明白,问题的关键在于getHandlerInternal渠道的Handler,继续追进去查看。
这是一个抽象类,点击看他实现方法的类有哪些,根据类图去查找一下。
根据类图,确定是AbstractHandlerMethodMapping类中的方法,接下来看实现。
getHandlerInternal
第一行代码也就是获取了请求用来匹配的地址。随后在lookupHandlerMethod中根据请求的地址找到了具体的处理方法,也就是具体的Controller方法。 随后取到了Handler就返回了。
doDispatch方法。
随后通过刚刚获取到的mappedHandler去获取HandlerAdapter,追进去看一下代码。
getHandlerAdapter
这里代码的意思去遍历当前类中的所有的Adapter,然后看哪个支持当前的handler。 当前类中有三个Adapter,一眼看过去,很明显我们的是RequestMappingHandlerAdapter,随后返回回去。
doDispatch方法。
接下来去调用applyPreHandle方法,此处追进去看一下。 在这里看到一个很眼熟的东西,interceptor,也就是请求拦截器,用过MVC的应该都有使用这个东西。
随后调用了HandlerAdapter的handle方法。
告一段落
这一篇文章先写到这里,再写下去文章太长了,不方便阅读,继续阅读关注下一篇文章,谢谢~
都看到这了,点个赞再走呗,宝~
结束语
写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。