源码剖析:web开发当中的参数解析原理

89 阅读2分钟

前言:在springboot注解当中,我们发现,只要给控制器方法的参数加上相应的注解,那么springboot就会自动把参数值给我们获取到,那么springboot底层到底是如何帮助我们获取参数的值呢?

首先我们打开DispatcherServlet这个类。我们知道任何请求都会被前端控 制器拦截。前端控制器里面有一个doDispatch方法来处理我们的请求。这 个方法里面有一个getHandler方法如下: 接下来我们来看一看底层原理是怎么实现的: image.png 那么Handler又交给谁处理呢?通过源码,我们发现前端控制器将Handler 交给处理器适配器处理,所以我们首先就要获取处理器适配器。 image.png 我们打断点进入到这个方法内部,发现: image.png 这个4个处理器就是处理不同的控制器方法。

其中第一个 @RequestMappingHandlerAdapter适配器。就是用来处理 @RequestMapping注解修饰的方法。 通过源码观察到,如何获取最合适的处理器适配器呢,就是循环遍历,获 取指定的适配器去处理控制器方法。 image.png 当找到适配器之后,通过适配器来进行handler的处理 image.png 那么这个handle方法是怎么处理的呢?我们可以点击进去看看。 image.png image.png 我们查询AbstractHandlerMethodAdapter类中的handle方法。 image.png 我们发现这个handle方法内部调用了一个handleInternal方法。我们进入 这个方法的内部处理细节。 我们进入RequestMappingHandlerAdapter类中的handleInternal方法 image.png 这个this.invokeHandlerMethod方法按照字面意思理解就是执行目标方 法。我们点击进去看看细节。 image.png 这个方法,首先我们关注参数解析器(this.argumentResolvers)。我们打断点进去看看。 image.png 参数解析器的作用就是确定将要执行的目标方法的每一个参数的值是什么; 我们通过参数解析器的名称可以确定:

RequestParamMethodArgumentResolver专门解析@RequestParam注 解修饰的参数值。

PathVariableMethodArgumentResolver 专门解析@PathVariable注解修 饰的参数值。 这些参数解析器都实现了一个接口: HandlerMethodArgumentResolver。 image.png supportParametrt:当前解析器是否支持解析这种参数

支持解析就调用 resolveArgument方法 接下来我们继续打断点,走到invokeAndHandle方法。这个方法字面意思 是执行并处理。我们进入这个方法内部: image.png 经过测试,我们得到了一个非常重要的结论: 当this.invokeForRequest方法执行之后,立马会执行我们的控制器方法。 也就是这个invokeRequest方法会真正执行我们的目标方法,那目标方法 到底是怎么执行的?我们进入这个方法。 image.png 我们发现:getMethodArgumentValues这个方法就是获取我们的参数 值,然后将参数值封装到Object[]数组中。然后调用this.doInvoke方法进 行执行。也就是按照反射的机制调用目标方法。我们查看doInvoke的具体 细节,看是不是使用反射的机制实现的。 image.png 我们发现通过一个反射工具类进行反射调用。 image.png 我们明白this.getMethodArgumentValues方法就是获取目标方法的参数 值。接下来我们就进入这个方法,探究目标方法的核心参数值是如何获取 的? image.png 我们设置一个测试,目标方法为 image.png 我们来看参数的详细信息: image.png 我们继续往下看,我们发现获取参数的详细信息之后,又声明了一个空的 object类型的数组。 image.png image.png 我们发现,获取到目标方法的详细参数信息之后,会循环遍历装载参数详 细的这个parameters数组。判断参数解析器是否支持解析这个参数。它是 怎么判断的?我们进入this.resolvers.supportsParameter(parameter))。 image.png 获取到参数解析器之后,如何判断对应的参数解析器是否支持解析参数 呢?我们进入supportsParameter方法内部。 image.png 由于我们第一个参数是@PathVariable注解修饰的。所以肯定交给对应的 PathVariableMethodArgumentResolver参数解析器来判断。 image.png 当我们的参数被参数解析器支持解析之后,接下来我们看看参数具体如何 解析的。 image.png 进入AbstractNamedValueMethodArgumentResolver类的resolveArgument 方法。 image.png 看看具体的实现 image.png image.png 我们发现目标方法的参数名称和参数值都存放在了一个map里面。map的 key就是参数名称,value就是参数值,我们可以通过key获取参数值。这样 我们的参数值就被解析出来了。这是springboot里面解析@PathVariable 注解的原理。 那么@RequestParam注解修饰的 参数如何解析?我们也可以看一看核心 的代码。 先定义一个控制器:

@RequestMapping("testRequestParam")
public String testRequestParam(@RequestParam("username") String username)
{   System.out.println(username);   return "hello"; }

image.png 其实和前面的@PathVariable差不多。 只不过参数解析交给RequestParamMethodArgumentResolver这个类的resolveName方法来处理了。 我们追踪核心源码:

String[] paramValues = request.getParameterValues(name);其实就是使用原生的servelet的方式 进行参数解析。 到这里我们springboot参数解析的原理就讲解完毕了。为了写这个文章憋了挺久的,看了好多资料,老是看不到下一步到哪,希望大家多多点赞。