SpringMvc源码探秘(三)请求是怎么到达Controller的(一)

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

目录

SpringMvc源码探秘(一)Tomcat启动项目时Spring做了什么
SpringMvc源码探秘(二)DispatchServlet初始化

前言

在上一篇文章中,我们讲到了DispatchServlet在init时做了哪些操作,这里先简单总结下。

  1. 创建WebApplicationContext
  2. 执行applicationContext的Refresh方法
  3. 执行DispatchServlet中的init开头的方法 包含但不限于以下方法。
  • initHandlerMappings
  • initHandlerAdapters
  • initViewResolvers
  • ....

正式开始

首先我们先回忆下web.xml的配置。 image.png 可以看下框出来的配置信息,大家应该都知道意思,url/开头的请求都进入DispatchServlet当中去。

所以这里要想一下Servlet的生命周期。
init方法初始化 -> service方法处理请求 -> doGet/doPost方法
也就是说,在浏览器上输入一个地址,会先进入service方法处理,根据请求方式判断,进入不同的请求方式处理方法。我这里发起一个简单的Get请求。

http://localhost:8080/spring_mvc_war_exploded/request

然后按照生命周期的标准去寻找doGet方法,但是我在DispatchServlet中并没有找到对应的方法,所以这个时候去看他的父类。 image.png 通过查看,所有的请求方法都指向一个processRequest方法,追进去看一下。

processRequest

image.png 方法刚开始,注册了一些参数,基本都是上面声明,下面方法就用到了,我们不去细扣方法里面的细节。

image.png catch里面的抛错误的我们就不看了,看到try里面一个doService方法,看样子是执行代码关键方法。随后值得注意的是在finally的最后的一行代码。广播一个RequestHandled事件,这里请求处理应该结束了,所以推送一个事件我们进去简单看一下。 image.png 推送的是一个ServletRequestHandledEvent,看这里这个样子应该可以用来做个简单请求日志记录,等文章结尾时,写一个事件监听器看一下。

doService 方法

image.png 这是一个抽象方法,我们直接看DispatchServlet中的实现即可。

image.png 方法一进入,打印了一个日志这里不用看。

image.png image.png 随后映入眼帘的就是一个If判断。判断条件也很简单,就是request当中有没有IncludeRequest这个属性,很明显,我们并没有设置这个属性,所以不用管他。返回的是False。
就算进入的话,看这个样子,就是向attributesSnapshot里面put一些数据,只不过这里我不知道put的是什么数据,无关紧要看下一段代码。

image.png 这里向request的属性中添加几个值,applicationContext、localeResolver、themeResolver、themeSource,第一个可以理解,其他的没见过也没用过,等遇到了再看是干嘛的,这里记住request中已经有几个属性就行了。

image.png 这一段代码和上一段代码同理,也是像request对象中放入属性,这里记住有这几个属性就行。

image.png 这一段代码没看懂是干嘛的,给外面声明的变量赋了个值,跳过吧,后面用到再说。

image.png 这是最后一段代码,try中里面一个doDispatch方法,和调用doService方法时一样,看来这是关键代码,下面的finally操作,就不看了没有什么具体的意义。

doDispatch方法

image.png 方法刚开始声明了一些变量,瞄一眼有个印象即可,下方代码中大概率还会用到赋值什么的。

image.png 这里主要看后面两个方法。checkMultipart方法看字面意思是检查是否Multipart,也就是是否是文件上传的Request,随后把这个里面返回的值赋值给了刚开头创建processRequest。也就是说这个里面可能会返回一个新的Request对象,跟进去简单扫一眼。 image.png image.png 果然,这里和我想的一样,如果请求是multipart的话,会重新创建一个Request返回出来,这样也就解释的通,最后那行代码为什么是ProcessedRequest != request了。

image.png 此处代码根据Request获取了Handler,需要追进去看一下代码。

getHandler

image.png 这个获取当前类下所有的HandlerMappings,通过Debug得知有两个。 image.png 看这里很容易可以看出来,我们需要调用的是RequestMappingHandler中的方法,接下来定位到这个类。
看一下RequestMappingHandlerMapping的一个类关系图,简单记一下后面有用。 image.png image.png 这个方法是在AbstractHandlerMapping类中的,我们直接追进去查看。

image.png 看到上述代码,即可明白,问题的关键在于getHandlerInternal渠道的Handler,继续追进去查看。

image.png 这是一个抽象类,点击看他实现方法的类有哪些,根据类图去查找一下。

image.png 根据类图,确定是AbstractHandlerMethodMapping类中的方法,接下来看实现。

getHandlerInternal

image.png 第一行代码也就是获取了请求用来匹配的地址。随后在lookupHandlerMethod中根据请求的地址找到了具体的处理方法,也就是具体的Controller方法。 image.png 随后取到了Handler就返回了。

doDispatch方法。

image.png 随后通过刚刚获取到的mappedHandler去获取HandlerAdapter,追进去看一下代码。

getHandlerAdapter

image.png 这里代码的意思去遍历当前类中的所有的Adapter,然后看哪个支持当前的handler。 image.png 当前类中有三个Adapter,一眼看过去,很明显我们的是RequestMappingHandlerAdapter,随后返回回去。

doDispatch方法。

image.png 接下来去调用applyPreHandle方法,此处追进去看一下。 image.png 在这里看到一个很眼熟的东西,interceptor,也就是请求拦截器,用过MVC的应该都有使用这个东西。

image.png 随后调用了HandlerAdapter的handle方法。

告一段落

这一篇文章先写到这里,再写下去文章太长了,不方便阅读,继续阅读关注下一篇文章,谢谢~

都看到这了,点个赞再走呗,宝~

结束语

写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。

猜你喜欢

转载自juejin.im/post/7086533270833201166