5.如何断点springboot(springmvc)如何解析参数

我这边用一个get请求来示例。这东西知道在哪断点查看,以后遇到问题可以快速定位。

我这里的接口是  http://localhost:8082/pathVariable2/2

代码是

  @GetMapping("/pathVariable2/{id}")
  public String pathVariable2(@PathVariable(value = "id")
      String id){
    return id;
  }

 

1.入口是httpservlet,然后到org.springframework.web.servlet.DispatcherServlet#doDispatch打断点

5.如何断点springboot(springmvc)如何解析参数

 

 2.这里2个关键方法

5.如何断点springboot(springmvc)如何解析参数

 

 第一是获取适配器

 第二个真正用适配器解析参数

2.1适配器一共4个,一般的请求用第一个就好

5.如何断点springboot(springmvc)如何解析参数

 

 2.2执行参数解析

1)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal  一路走下去

2)org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod 一路走下去

5.如何断点springboot(springmvc)如何解析参数

 

 520:这里是拿到所有的参数解析器:最终是遍历所有的参数解析器去解析参数的

0 = {RequestParamMethodArgumentResolver@6898}
1 = {RequestParamMapMethodArgumentResolver@6899}
2 = {PathVariableMethodArgumentResolver@6900}
3 = {PathVariableMapMethodArgumentResolver@6901}
4 = {MatrixVariableMethodArgumentResolver@6902}
5 = {MatrixVariableMapMethodArgumentResolver@6903}
6 = {ServletModelAttributeMethodProcessor@6904}
7 = {RequestResponseBodyMethodProcessor@6905}
8 = {RequestPartMethodArgumentResolver@6906}
9 = {RequestHeaderMethodArgumentResolver@6907}
10 = {RequestHeaderMapMethodArgumentResolver@6908}
11 = {ServletCookieValueMethodArgumentResolver@6909}
12 = {ExpressionValueMethodArgumentResolver@6910}
13 = {SessionAttributeMethodArgumentResolver@6911}
14 = {RequestAttributeMethodArgumentResolver@6912}
15 = {ServletRequestMethodArgumentResolver@6913}
16 = {ServletResponseMethodArgumentResolver@6914}
17 = {HttpEntityMethodProcessor@6915}
18 = {RedirectAttributesMethodArgumentResolver@6916}
19 = {ModelMethodProcessor@6917}
20 = {MapMethodProcessor@6918}
21 = {ErrorsMethodArgumentResolver@6919}
22 = {SessionStatusMethodArgumentResolver@6920}
23 = {UriComponentsBuilderMethodArgumentResolver@6921}
24 = {PrincipalMethodArgumentResolver@6922}
25 = {RequestParamMethodArgumentResolver@6923}
26 = {ServletModelAttributeMethodProcessor@6924}

所以可以分析的出,我这个接口用PathVariableMethodArgumentResolver来解析,这是后话,肯定是哪所有解析器一个个去解析的。

524:拿到所有的返回值处理器

0 = {ModelAndViewMethodReturnValueHandler@6340}
1 = {ModelMethodProcessor@6341}
2 = {ViewMethodReturnValueHandler@6342}
3 = {ResponseBodyEmitterReturnValueHandler@6343}
4 = {StreamingResponseBodyReturnValueHandler@6344}
5 = {HttpEntityMethodProcessor@6345}
6 = {HttpHeadersReturnValueHandler@6346}
7 = {CallableMethodReturnValueHandler@6347}
8 = {DeferredResultMethodReturnValueHandler@6348}
9 = {AsyncTaskMethodReturnValueHandler@6349}
10 = {ServletModelAttributeMethodProcessor@6350}
11 = {RequestResponseBodyMethodProcessor@6351}
12 = {ViewNameMethodReturnValueHandler@6352}
13 = {MapMethodProcessor@6353}
14 = {ServletModelAttributeMethodProcessor@6354}

3)继续断点,核心执行解析是553行

5.如何断点springboot(springmvc)如何解析参数

 

 4)org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

5.如何断点springboot(springmvc)如何解析参数

 

 52行真正执行目标方法,我们进去

5)继续断点org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest

5.如何断点springboot(springmvc)如何解析参数

 

 56行获取参数  61行反射执行方法。所以我们得进入56行

6)org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues 方法

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; } }

6-1)判断参数解析器是否支持这种参数解析

5.如何断点springboot(springmvc)如何解析参数

 

 遍历27个参数解析器,看看哪个支持。然后break掉

 

 最终发现是PathVariableMethodArgumentResolver支持

org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver#supportsParameter

  public boolean supportsParameter(MethodParameter parameter) {
//不是PathVariable注解的不行 if (!parameter.hasParameterAnnotation(PathVariable.class)) { return false;
//不是map开头的可以 } else if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) { return true;
//其他情况的考虑 } else { PathVariable pathVariable = (PathVariable)parameter.getParameterAnnotation(PathVariable.class); return pathVariable != null && StringUtils.hasText(pathVariable.value()); } }

6-2)真正去解析参数的值

  @Nullable
  public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//获取参数解析器 HandlerMethodArgumentResolver resolver = this.getArgumentResolver(parameter); if (resolver == null) { throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]. supportsParameter should be called first."); } else { return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); } }
  public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
//获取参数对象 AbstractNamedValueMethodArgumentResolver.NamedValueInfo namedValueInfo = this.getNamedValueInfo(parameter);
//确认需要解析的参数名字 MethodParameter nestedParameter = parameter.nestedIfOptional(); Object resolvedName = this.resolveEmbeddedValuesAndExpressions(namedValueInfo.name); if (resolvedName == null) { throw new IllegalArgumentException("Specified name must not resolve to null: [" + namedValueInfo.name + "]"); } else {
//真正去解析参数的值 Object arg = this.resolveName(resolvedName.toString(), nestedParameter, webRequest);

 

5.如何断点springboot(springmvc)如何解析参数

 

 类名是:PathVariableMethodArgumentResolver 通过它来解析

uriTemplateVars是请求头带过来的值id=2

这样最终得到参数的值是2

上一篇:Windows部分常用API


下一篇:状态模式在实现怪物ai中的运用