1、请求映射原理

  • 所有的请求都会经过DispatcherServlet这个类,先了解它的继承树

本质还是httpServlet

  • 原理图

  • 测试

    request请求携带的参数

​ 从requestMapping中寻找请求方法

就可以获取到请求的方法

​ 拿到这个方法后最终会调用DispatchServlet

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

​ 然后调用AbstractHandlerMethodAdapter的handleInternal()方法,被RequestMappingHandlerAdapter实现

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav;
checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}

​ 主要调用invokeHandlerMethod(request, response, handlerMethod);方法

invocableMethod.invokeAndHandle(webRequest, mavContainer);

​ 再调用invokeAndHandle()方法

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}

​ 在通过doInvoke(args);实现方法的调用

@Nullable
protected Object doInvoke(Object... args) throws Exception {
Method method = getBridgedMethod();
try {
if (KotlinDetector.isSuspendingFunction(method)) {
return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
}
return method.invoke(getBean(), args);
}
.......

method.invoke(getBean(), args);这就是通过反射实现方法的调用

2、请求参数注解处理原理

原理图

  1. 先得到请求的request

  1. 在获取可以处理请求的方法的Mapping映射器

     DispatcherServlet中的
    doDispatch方法
    // Determine handler for the current request.
    mappedHandler = getHandler(processedRequest);
  2. 判断每个参数带有注解是哪个,是否存在相应的解析器

    • 寻找合适的处理适配器

       DispatcherServlet中的
      doDispatch方法
      // Determine handler adapter for the current request.
      HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

  • 寻找可以处理相应注解的处理器
第一步
DispatcherServlet中的
doDispatch方法
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 第二步
RequestMappingHandlerAdapter中的
handleInternal方法
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
invokeHandlerMethod方法
invocableMethod.invokeAndHandle(webRequest, mavContainer); 第三步
ServletInvocableHandlerMethod中的
invokeAndHandle方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); 第四步
InvocableHandlerMethod类中的
invokeForRequest方法
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);//获取请求的参数 第五步
InvocableHandlerMethod类中的
getMethodArgumentValues方法
if (!this.resolvers.supportsParameter(parameter)) {//寻找处理相关注解的处理器,并保存到缓存中 supportsParameter(parameter)从这里进入的
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
} 第六步
HandlerMethodArgumentResolverComposite类中的
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result =
this.argumentResolverCache.get(parameter);//从缓存中获取,开始肯定没有
if (result == null) {
//增强for循环中选择合适的处理器 27个
for (HandlerMethodArgumentResolver resolver :
this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
//保存到缓存中
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}

  • 通过注解处理器获取参数

    第一步
    InvocableHandlerMethod类中的
    getMethodArgumentValues方法 try {
    args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); //真正开始获取参数
    } 第二步
    HandlerMethodArgumentResolverComposite类中的
    resolveArgument方法中
    //获取参数对应注解的处理器
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    getArgumentResolver方法中
    //从缓存中获取,由于开始的之前往缓存中存入了,所以现在可以直接拿,如果没有下面还有可以循环寻找
    HandlerMethodArgumentResolver result =
    this.argumentResolverCache.get(parameter); AbstractNamedValueMethodArgumentResolver类中的
    resolveArgument方法
    Object resolvedName =
    resolveEmbeddedValuesAndExpressions(namedValueInfo.name);//获取参数名
    Object arg = resolveName(resolvedName.toString(),
    nestedParameter, webRequest);//获取参数值 //具体怎么获取
    PathVariableMethodArgumentResolver类中的
    resolveName方法
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(//直接从request请求域中获取
    HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
    return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);//在通过参数名称确定是哪一个
    }
  • 获取参数完成后,会调用InvocableHandlerMethod来中的doInvoke方法继续反射调用方法

    InvocableHandlerMethod类中的
    doInvoke方法
    return method.invoke(getBean(), args);

Spring 请求方法的调用原理(Controller)和请求参数的获取的原理的更多相关文章

  1. 关于ASP.NET中WEBAPI中POST请求中FromBody修饰的string类型的参数服务器端获取不到值FromBody空值的简单解决方法

    其实解决办法很简单,就是POST请求的时候,来自实体的参数,content-type:application/x-www-form-urlencoded情况下,是默认按照键值对来解析的,比如param ...

  2. SpringBoot中Post请求提交富文本数据量过大参数无法获取的问题

    yml增加配置 # 开发环境配置 server: tomcat: max-http-form-post-size: -1

  3. Spring MVC中基于注解的 Controller

         终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响 ...

  4. springMVC学习总结(二)路径映射和请求方法限定

    springMVC学习总结(二)路径映射和请求方法限定 一.路径映射 无参数的访问路径 对springmvc项目的访问路径,是由根路径和子路径组成:在注解式开发中,根路径标注在类名之上,子路径标注在方 ...

  5. HTTP请求方法

    HTTP请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, ...

  6. HTTP状态码、请求方法、响应头信息

    HTTP状态码 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求.当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应 ...

  7. HTTP请求方法

    HTTP请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, ...

  8. HTTP-Runoob:HTTP请求方法

    ylbtech-HTTP-Runoob:HTTP请求方法 1.返回顶部 1. HTTP请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, PO ...

  9. HTTP协议中request报文请求方法和状态响应码

    一个HTTP请求报文由4部分组成: 请求行(request line) 请求头部(header) 空行 请求数据 下图给出了请求报文的一般格式: 请求行中包括了请求方法,常见的请求方法有: GET:从 ...

随机推荐

  1. unity---世界坐标和本地坐标的转换

    会受到缩放的影响 用的比较多的是 本地坐标转换为世界坐标,比如在自己周围释放物体 当物体发生旋转,方向会发生变化

  2. 论文解读(SCGC))《Simple Contrastive Graph Clustering》

    论文信息 论文标题:Simple Contrastive Graph Clustering论文作者:Yue Liu, Xihong Yang, Sihang Zhou, Xinwang Liu论文来源 ...

  3. Django序列化组件与数据批量操作与简单使用Forms组件

    目录 SweetAlert前端插件 Django自带的序列化组件 批量数据操作 分页器与推导流程 Forms组件之创建 Forms组件之数据校验 Forms组件之渲染标签 Forms组件之信息展示 S ...

  4. springcloud-- Alibaba-nacos--支持的几种服务消费方式

    通过<Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现>一文的学习,我们已经学会如何使用Nacos来实现服务的注册与发现,同时也介绍如何通过LoadBal ...

  5. 可变数组Vector

    package com.demon.languang.business.rest; import java.util.Vector; public class DemonTest { @Suppres ...

  6. 小样本利器1.半监督一致性正则 Temporal Ensemble & Mean Teacher代码实现

    这个系列我们用现实中经常碰到的小样本问题来串联半监督,文本对抗,文本增强等模型优化方案.小样本的核心在于如何在有限的标注样本上,最大化模型的泛化能力,让模型对unseen的样本拥有很好的预测效果.之前 ...

  7. Python数据分析--Numpy常用函数介绍(6)--Numpy中与股票成交量有关的计算

    成交量(volume)是投资中一个非常重要的变量,它是指在某一时段内具体的交易数,可以在分时图中绘制,包括日线图.周线图.月线图甚至是5分钟.30分钟.60分钟图中绘制. 股票市场成交量的变化反映了资 ...

  8. Kubernetes将弃用Docker!与 containerd容器引擎

    时间戳:2022-06-07 20:32:19 星期二 撰写文档参考:(阿良-腾讯课堂)Kubernetes将弃用Docker 参考博客k8s入坑之路(3)containerd容器 container ...

  9. 面试突击58:truncate、delete和drop的6大区别

    在 MySQL 中,使用 truncate.delete 和 drop 都可以实现表删除,但它们 3 个的使用场景和执行效果完全不同,接下来我们来盘点一下. truncate.delete.drop区 ...

  10. 关于kali安装输入法

    之前老是被kali大小写输入恶心坏了,正好看到一篇文章写kali安装搜狗输入法的,虽然不需要输入中文,但是英文输入就很方便了. 一.切换root用户登录 1.sodu su切换为root权限 2.pa ...