各种类型参数解析源码入门分析
因为我们的请求会被DispatcherServlet拦截下来,所以我们如果要进行分析我们的请求参数如何被传入到我们的controller方法的参数中的话,那么肯定需要分析DispatcherServlet
我们接下来分析DispatcherServlet中的doDispatcher方法
我们来以debug的方式运行

使用debug来分析他是如何解析出

这些值的


然后我们进入到这个方法查看

这个方法就是用于判断我们的请求是使用哪一个handler进行处理的,前面我们在说controller的映射原理的时候也提到过,这里有五个默认的handler

它会使用这个for循环来循环判断,他根据我们的原生request来判断我们哪个handler能够处理我们的这个请求,他就返回哪个handler。handler能够处理是因为里面包含了contoller方法的映射信息
如下图:返回的handler就包含了我们要访问的controller的信息描述,也就是意味着现在我们已经找到哪个方法可以处理我们的请求了

然后我们继续往下看
Handler适配器(HandlerAdapter)

这个方法的作用就是确定我们的handler对应的适配器,解释一下这个适配器是用于干什么的
因为我们在上面已经知道我们这个请求想要访问的controller方法是什么了,此时springMVC会利用反射的机制来确定方法的参数,然后执行方法等等一系列繁琐的操作,所以springMVC帮助我们建立了一个适配器类,用于处理这些事情。
最终springMVC会使用这个适配器来调用hand方法处理我们目标方法
我们先来看一看这个HandlerAdapter接口
这个接口中有三个方法


supports方法用于判断传入的handler是否支持处理
我们以后可自定义一个适配器,只要实现这个HanderAdapter接口,然后覆盖重写这个suports,我们就可以在这个suports中自己定义我们的支持哪些handler即可。
然后我们回过头来看这个getHandlerAdapter方法

可以看到有四个handlerAdapters。然后根据传入进来的handler判断哪个适配器可以处理它
这四个适配器分别是

第一个RequestMappingHandlerAdapter是用于支持@RequestMapping注解的
第二个HandlerFunctionAdapter是用于支持函数式编程的
而我们的controller方法默认都是找的第一个适配器
我们接着debug
然后它会循环判断这个适配器是否支持这个handler

我们进入到它实现的supports方法中看他是如何判断是否支持的

我们发现它先使用instanceof关键字判断handler是不是一个HandlerMethod 的子类,因为参数是Object类型的,如果是的话再将这个handler强转为HandlerMethod执行supportsInternal这个方法判断是否支持
我们使用idea的计算器查看他传入过来的这个handler是个什么类型的

正是一个HandlerMehtod类的
然后看supportsInternal这个方法

它只要传入的是一个HandlerMethod类型的参数返回的就是一个true
所以最终这个判断适配器是否是用于处理handler的方法返回的结果就是一个true


然后我们往下执行,执行到这一行

看到这个注解说这个是实际调用的handler
这个ha就是我们筛选获取到的HandlerAdapter
然后我们进入这个方法

发现它使用了一个handleInternal方法,然后再进入这个handleInternal方法

而我们只需要关注这里面的invokeHandlerMethod方法即可因为是这个方法返回的mav这个值,这个mav就是return出去的那个

这个方法的作用是用于执行目标方法,就是执行我们请求对应的controller方法
进入这个invokeHandlerMethod方法

参数解析器
我们可以看到这个方法,这个方法翻译过来叫做参数解析器

经过计算发现这个参数解析器总共有27个
这个参数解析器的作用解释我们将要执行的目标方法的每一个参数的值是什么
像第一个解析器顾名思义,用于解析@RequestParam参数的
点开第一个我们可以看到有两个被RequestParam修饰的参数

分别时索引为5和6的
我们查看我们的controller方法

索引为5和6正好是requestparam注解
我们点开一个验证,发现索引为5的这个就是age

其实我们的参数解析器是一个接口,这个接口叫做HandlerMethodArgumentResolver

这个接口有两个方法分别时supportsParameter、resolveArgument方法
如果解析器执行,那么就是两步,先判断当前解析器是不是支持传入进来的这个参数的解析,如果支持解析的话就会调用resolveArgument方法来解析
返回值处理器
然后回到这个invokeHandlerMethod方法

他还有一个返回值处理器,这个返回值处理器经过计算总共有15个

我们就可以看到一些我们很熟悉的处理返回值的一些方式,像ModelAndView、Mode、View这些都是处理返回结果的方式
我们的参数解析器和返回值处理器最终都被放入了ServletInvocableHandlerMethod invocableMethod这个就是我们的目标方法的一个包装起来得类,本质上还是我们的目标方法,我们来计算一下我们的这个invocableMethod,它包含了我们的参数解析器、返回值处理器、参数信息等内容

然后我们继续执行invokeHandlerMethod方法,
执行到这里

我们来关注这个方法,因为这个方法就是调用并且处理方法
进入到这个方法

然后我们能看到这个方法invokeForRequest

如果我们将这行代码放行,那么他就会找到我们请求的controller方法
我们来给controller中的这个getCar方法打上断点

这个方法下面的一行也打上断点,为了判断他是跳转到下一行还是跳转到这个getCar方法中

然后我们放行

果然它先来到了controller中的对应方法
,然后再次放行

它就回到了这一行,这就意味着真正实行目标方法的的方法。
而真正执行目标方法就意味着需要将参数的值传入进来
然后我们继续debug
进入这个方法

然后我们中于看到了这一行代码

获取参数的值,然后进入到这个方法


但是此时只是获取参数的详细信息,但是并没有赋值

这个数组就是用于装参数确定好的值
然后往下执行

这个方法用于判断解析器是不是支持这个参数的解析
我们进入这个方法查看

然后再进入这个方法getArgumentResolver

我们可以看到

它这里使用了增强for来挨个确定哪个参数解析器可以解析我们传入的这个参数,直到找到这个参数然后返回出去
然后解析这个参数的值,通过下面这个方法

我们进入到这个方法查看

首先获取到当前这个参数对应的解析器,这个解析器就是我们上一步获取到的那个
然后继续执行代码

进入这个方法


然后我们进入到resolveEmbeddedValuesAndExpressions方法

最终返回的是我们需要解析的参数名字

然后执行下面这个方法

这个方法用于根据参数名获取它的值
进入这个方法

我们发现

它这里获取到了请求参数中的值,并且是从request域中获取的,这时因为我们再一开始UrlPathHelper这个类当请求一进来,会帮我们把请求路径中的请求参数都存入到request域中,所以这里可以直接找从request域中找到这个值,所以最终获取到了参数的值
然后后面接着再getMethodArgumentValues这个方法中循环解析

浙公网安备 33010602011771号