Spring源码梳理--SpringMVC是怎样解析请求参数的
SpringMVC是怎样处理一个请求的在前面有写,这里就不在重复,以后再去描叙的更有条理一些。这里说下SpringMVC是怎样解析url上的请求参数的。
请求的URL: http://localhost:8080/hello?name=jhf&age=16
Controller :
@RestController public class MyController { @RequestMapping(value = "hello",method = RequestMethod.GET) public String hello(@RequestParam String name, @RequestParam Integer age) { return "Hello " + name + " - " + age; } }
然后我们直接从 DispatcherServlet 的 doDispatch 方法开始:
然后到Adapter的handle方法:
这里我们需要知道HandlerMethod类(
理解为对
RequestMapping(value = "hello",method = RequestMethod.GET)
public String hello(@RequestParam String name, @RequestParam Integer age) 方法的封装
):
public class HandlerMethod { protected final Log logger = LogFactory.getLog(this.getClass()); private final Object bean; @Nullable private final BeanFactory beanFactory; private final Class<?> beanType; private final Method method; private final Method bridgedMethod; private final MethodParameter[] parameters; @Nullable private HttpStatus responseStatus; @Nullable private String responseStatusReason; @Nullable private HandlerMethod resolvedFromHandlerMethod; @Nullable private volatile List<Annotation[][]> interfaceParameterAnnotations; private final String description;
这些属性差不多可以见名知意,再看下具体的值就知道了,不过多叙述了:
然后可以看到parameters属性有两个,MethodParameter就是描叙Controller方法的请求参数的:
在adapter的invokeHandlerMethod方法 会通过HandlerMethod对象产生一个:ServletInvocableHandlerMethod对象:
然后执行此对象:
然后到这里就是真正去执行Handler了:
两步: 第一步就是获取执行方法的请求参数,第二步就是执行方法。 这篇文章主要是梳理下是怎样获取请求参数的。
有两个参数:
但我们可以看到其属性的值:parameterName是空的。下面就是将其名称填进去,看其表示的是name,还是age。
我们看下这个resolvers
这两个方法表示的是,支不支持解析这个MethodParameter。
支持的话就用resolveArgument方法去解析:
我们再看下HandlerNethodResolver是怎样去判断的(Annotation表示的是注解):
1、类RequestHeaderMethodArgumentResolver
2、类RequestParamMethodArgumentResolver
通过RequestParam可以知道我们这里应该用的Resolver就是RequestParamMethodArgumentResolver
我们再看下是怎样解析方法所需的参数名称的:
这里就是将RequestParam注解中的内容填充进来:
这里有两个方法:createNamedValueInfo、updateNamedValueInfo。
createNamedValueInfo就是将你在RequestParam注解中的内容写到NameValueInfo中。
updateNamedValueInfo:
如果你在注解中没有写name,就会调:parameter.getParameterName();去获取,这里就会有些复杂了,第一次获取时其要通过解析class文件去获取(因为方法的测试名编译时应该是用arg0、arg1表示的,并不是我们写的String name,Integer age,根据以往看到有些内容确认的,并没有通过具体的验证,这个地方现在不能确认为什么还要通过读取解析class文件去获取方法的具体参数名),所以我们在用RequestParam注解时还是将name写上比较好。
解析之后我们再来看下MethodParameter类:
type与name已经有啦。
获取到名称后,接下来就是从request中去获取对应的值了:
直接从request中获取(前面还会有其它一些情况获取返回,这里说下普通情况,看下其流程):
这里这里获取的value就是String类型,但是我们的入参会有其它的类型,如Integer、Long等,所以还需要进行类型转换。
关于转换的知识点之后再写。