探究springBoot是如何去解析获取各种类型参数请求的原理
[1]测试请求地址:http://localhost:8080/car/5/owner/6
对应的控制器代码
@RestController
public class TestController {
@GetMapping("/car/{id}/owner/{username}")
public Map<String, Object> test(@PathVariable("id") String id,
@PathVariable("username") String username) {
Map<String, Object> map = new HashMap();
//返回请求路径中的参数
map.put("id", id);
map.put("username", username);
return map;
}
}
[2]打断点{启动debug调试}
通过全局搜索{ps:快捷键是按两下shift} 查询DispatcherServlet整个类
{ps:DispatcherServlet相当于一个分发器(就是一个Servlet)}
找到doDispatch方法{ps:该方法就相当与做一个调度}
记得打上断点{在WebAsyncManager-Web异步管理器这里(主要用来管理异步请求的处理。)}
[3]开始启动调试
启动程序
输入网址
[4]获得执行程序执行链(关于如何映射到方法的)
{ps:所有的映射地址对应的方法都在这个mappingRegistry注册中心当中}
[5]核心部分--处理器的适配器
①HandlerAdapter
getHandlerAdapter方法
- 0 - 支持方法上标注@RequestMapping
- 1 - 支持函数式编程
- ...
适配器判断(通过判断当前传入的是否是Handler类型,来判断是否支持适配器)
最后为其找个一个适配器 RequestMappingHandlerAdapter
②执行目标方法
查看内部处理细节(进入RequestMappingHandlerAdapter)
RequestMappingHandlerAdapter-开始执行目标方法了
进入invokeHandlerMethod中查看目标方法如何执行的
我们会发现在可执行方法invocableMethod中设置了一个参数解析器
参数解析器-HandlerMethodArgumentResolver
HandlerMethodArgumentResolver参数解析器核心如下
确定将要执行的目标方法的每一个参数的值是什么;
SpringMVC目标方法能写多少种参数类型。取决于参数解析器。
HandlerMethodArgumentResolver接口的中的两个方法如下
- supportsParameter判断当前解析器是否支持这种参数
- 支持就调用解析方法resolveArgument
返回值处理器-HandlerMethodReturnValueHandler
RequestMappingHandlerAdapter-真正执行目标执行方法
如何确定目标方法每一个参数的值(核心代码如下)
============InvocableHandlerMethod==========================
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
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;
}
}
}
return args;
}
}
挨个判断所有参数解析器哪个支持解析找个参数
PS:在得到参数解析器是会先找缓存
===================HandlerMethodArgumentResolverComposite==========================
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = (HandlerMethodArgumentResolver)this.argumentResolverCache.get(parameter);
if (result == null) {
Iterator var3 = this.argumentResolvers.iterator();
while(var3.hasNext()) {
HandlerMethodArgumentResolver resolver = (HandlerMethodArgumentResolver)var3.next();
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, resolver);
break;
}
}
}
return result;
}
解析找个参数的值
调用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法即可