从以前的文章中可以知道,在请求进行处理的过程中,要一步步的找到对应的handler,具体的过程见下面的这篇文章。找到handler是找到当前的请求会调用哪个方法。
找到handler的过程
在找到哪个handler处理该请求后,要找一个处理器的适配器。 RequestMappingHandlerAdapter。
第一个处理器适配器是支持方法上标注@requestMapping注解的。
第二个是支持函数式编程的。
第三个和第四个是支持其他的。
下面是看当前的处理器适配器支不支持处理该handler。
判断生效
因此会得到第一个处理器适配器。
然后判断是不是get方法和head,是不是浏览器缓存,然后调用处理器适配器的handle方法进行处理。
然后调用handleInternal()。
然后回到了RequestMappingHandlerAdapter这个类里面。
然后调用这个类里面的invokeHandlerMethod方法。翻译过来是执行处理器方法。
进入到这个方法中。
argumentResolvers的意思是参数解析器,在这个类中,会根据参数的类型配置相应的参数解析器。
一共是27个参数解析器。
参数解析器由两个接口组成。
因此分为两步,第一步是判断当前的解析器能不能够解析当前的参数,第二步是进行解析。
returnValueHandlers代表的是返回值处理器,也就是说能够处理多少中返回值,一共15种。
springboot会将这些参数解析器和返回值处理器封装到invocableMethod中。
然后来到下面的这个方法。
然后来到下面的这个方法。
上面的方法是执行请求,下面的这个方法是得到请求中参数的值。
保存在args这个数组中。
那么参数的值是如何确定的哪?进入上面的这个方法,具体的过程是下面的这段java代码。
============InvocableHandlerMethod==========================
MethodParameter[] parameters = this.getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
Object[] args = new Object[parameters.length];
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
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 (logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
从上面的这段代码中我们可以看出来,首先是得到方法的参数数组,然后判断方法的参数数组是否为空,不为空则创建一个和参数数组一样大的数组,然后挨个遍历参数数组,找到合适的参数解析器。
if (!this.resolvers.supportsParameter(parameter))
上面的这个代码是判断当前的26个参数解析器是否可以解析当前的参数,进入上面的代码。
再进入。
从上面的代码可以看出来while循环是判断26个参数解析器是否可以解析当前的参数,以及哪个可以解析当前参数,并且将参数解析器放到缓存中,当次下一次使用的过程中便会非常的快。
当判断完支持后,便开始进行解析参数。
深入上面的代码,会进入下面的代码。
解析器会调用resolveArgument方法,进入这个方法。
上面的这行代码是得到参数的名字。
下面的这一行是解析参数的值
具体过程进入上面的函数,就是下面的方法。
先进行一个判断,然后将再urlpathhelper中存储的值放到其中,这就是解析参数的值。
然后进行上面的遍历循环,看哪个解析器可以解析当前的参数,然后进行解析。