一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
目录
SpringMvc源码探秘(一)Tomcat启动项目时Spring做了什么
SpringMvc源码探秘(二)DispatchServlet初始化
SpringMvc源码探秘(三)请求是怎么到达Controller的(一)
SpringMvc源码探秘(三)请求是怎么到达Controller的(二)
前言
在上一章节中,知道了请求是怎么通过DispatchServlet最后到达Controller方法的。我们都知道请求时会写带请求参数,在上一篇的阅读中,也看到resolveArgument方法,但是我们没有仔细的进去阅读,我们本篇文章的目的就是搞懂,Spring是如何帮我们转换这个参数的。
正式开始
在上一篇文章里,有看到在InvokeHandlerMethod中,向最终的执行方法的类,设置了ArgumentResolvers,所以此时的argumentResolvers是在RequestMappingHandlerAdapter的。
随后在具体使用到时候,是通过遍历argumentResolvers来找到最终的argumentresolver,然后来解析参数,那么这里遍历的究竟是哪些参数解析器还是需要看他创建时放入了哪些解析器。
追根溯源,在RequestMappingHandlerAdapter中点击这个argumentResolvers属性过去查看后发现,这个属性默认是一个Null,所以这里会有初始化方法,既然知道是初始化,那么绝对逃不开构造方法、静态代码块这些,所以我们这里一个一个去查看一下。
构造方法
看了当前的这个构造方法,好像并没有和我们想要的argumentResolver扯上关系,随后查找一下,当前类也没有静态代码块,于是我陷入了思考。
我突然想到,这个类在初始化的时候,创建方式什么样的,既然这里是SpringMVC,应该会把对象交给SpringIOC去创建吧,由于initHandlerAdapter的方法我并没有看过,于是我去翻了一下DispatchServlet中的initHandlerAdapters方法,并且找到了答案。
DispatchServlet中的initHandlerAdapters方法
通过调用了getDefaultStrategies方法,获取到了HandlerAdapters,这里追进去看一下。
方法刚开始,加载了一个配置文件,这个配置文件我们从来没设置过,也就说这个配置文件是在Spring项目内部本身就有的,我在当前模块下的Resources目录找到这个文件。
通过这个文件可以看出来,通过Class的完整类名可以获取一堆class。随后创建,我们只要看创建后的代码即可。
也就是这一行代码,根据字面意思是创建什么什么,这里方法把ApplicationContext和当前要创建的类的Class放入了这个方法。追进去看一下。
OK了到这里就明了了,获取了BeanFacotry,然后调用createBean方法。也就是说,这里所有获取到的HandlerAdapter都会被注册到Spring容器中,也就是会进入SpringBean的生命周期。
回到RequestMappingHandlerAdapter类中,发现了一个有用信息。
该类实现了InitializiingBean接口,这个实现的方法afterPropertiesSet方法,就是在init-method方法执行完成之后,执行的一个初始化方法,这里我们进入看一下这个方法在此类中作了什么。
afterPropertiesSet
看这个方法就很清晰了,通过getDefaultAgrumentResolvers方法,获取默认的参数解析器。
看到这里是不是就看到了很多眼熟的东西,想我框出来的这些。RequestParam注解、PatchVariable注解、RequestBody和ResponseBody注解,还有ServletRequest和ServletResponse。
现在知道,参数解析器有哪些了,我们回到调用controller前获取参数的那个方法,再次一探究竟。
getMethodArgumentValues
他这个里面一共经历了几个步骤。
- 获取形参列表
- 遍历形参列表
- 根据遍历到的当前的参数,去调用argumentResolvers的supportsParamter方法,来判断是否有支持当前参数的参数解析器。
- 根据遍历到的当前的参数,去调用argumentResolvers的resolveArgument方法,获取这个值。
我们这里简单的看个ArgumentResolver的代码,其他的有兴趣的,大家可以自行阅读一下。
RequestResponseBodyMethodProcessor
这个类是用来解析RequestBody注解的,我们先看下他的supportsParameter方法吧。
supportsParameter
比较简单,直接就判断了当前参数上有没有RequestBody的注解。没有就返回false了。
resolveArgument
由于追进去的代码,过于庞大我截取转换部分的关键代码,看一下即可,具体的转换方法在readWithMessageConverters方法中。
在这一段确定了参数要转换的Class。
通过read方法,最终读取到最终的对象。
read方法有以下的几个实现,很明显,我们要看的AbstratHttpMessageConverter的read方法。
调用readInternal方法,这个方法是一个抽象方法。
接下来就到具体的JSON解析环节了我这里就不继续追了,我们了解到这里就可以了。
留一个思考题
这个时候我们可以思考一个问题,我们能不能自定义一个ArgumentResolver呢,来解析一些特定的类,比方说Token,实现不用在业务代码里token转换实体类呢,欢迎大家评论区讨论。
告一段落
到这里了,这一篇文章就结束了,上面留的思考题,我在下一章,会进行讲解。希望看完这篇文章大家都能有一点收获。
都看到这了,点个赞再走呗,宝~
结束语
写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。