六、请求处理—获取请求参数系列注解是怎样工作的?
在Spring MVC中,有许多常用的注解,我们给方法的参数前边标注这些注解,Spring MVC就会帮我们按照要求,在调用目标方法的时候,帮这些参数确定好值,我们就可以在下边使用了,总结如下:
@PathVariable -->(获取路径变量)
@RequestHeader -->(获取请求头)
@RequestParam -->(获取请求参数)
@CookieValue -->(获取cookie值)
@RequestBody -->(获取请求体[POST])
@RequestAttribute -->(获取request域属性)
@MatrixVariable -->(矩阵变量)
我们已经很熟练的使用这些注解了,但是,这其中的原理是什么,你知道吗?
同样,来到处理所有请求的入口 DispatcherServlet 的 doDispatch() 方法
这里是上一片看过的请求映射部分,找到了这个请求对应的handler,这里就不在赘述了,继续往下看
找到适配器以后,看他要干什么
再往下走,来到 handle 这个关键方法,这个方法传入了request、response和我们的目标方法,它来帮我们执行目标方法,如下
继续点击step into,就会来到 RequestMappingHandlerAdapter 类的 handleInternal() 方法,然后来到这个方法的 invokeHandlerMethod() 调用,来执行目标方法
进入这个方法
参数解析器是一个接口,里边有两个方法,作用如下
参数解析器下边还有一个返回值处理器,默认15种
Spring mvc提前帮我们把这些解析器、处理器都放到了 ServletInvocableHandlerMethod 里边,继续往下走,跳过中间一些不重要的,直接来到真正执行目标方法的方法
进入这个方法,如下
我们来看这一行代码里边做了什么,如何执行目标方法的
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//获取方法上所有参数的详细信息
MethodParameter[] parameters = this.getMethodParameters();
//判空,没有参数列表就直接返回
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
//这里new了一个参数个数长度的Object数组
Object[] args = new Object[parameters.length];
//挨个遍历
for(int i = 0; i < parameters.length; ++i) {
//拿到第i个参数
MethodParameter parameter = parameters[i];
//初始化
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
//判断当前解析器是不是支持这种参数类型
//就是遍历前边的那26个参数解析器,看谁支持当前参数
//找到之后放入缓存
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//从缓存拿对应的解析器,进行解析
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} catch (Exception var10) {
if (this.logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
this.logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
接下来接没有必要再跟进去了,里边就到我们的反射工具类了。
经过一步一步的debug,我们终于搞明白那些参数注解是怎样获取值的,其实原理也很简单,就是找到自己匹配的参数解析器,解析出请求参数而且,多debug几遍也就轻车熟路了。