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. 好客租房22-react组件的两种创建方式(类组件)

    2.2使用类创建组件 类组件:使用ES6的class创建的组件 约定1:类组件必须以大写字母开头 约定2:类组件应该继承react.component父类 从中可以使用父类的方法和属性 约定3:组件必 ...

  2. 安装Squid到CentOS(YUM)

    运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:无 硬件要求:无 安装过程 1.关闭防火墙和SeLinux [root@localhost ~] ...

  3. 协议层安全相关《http请求走私与CTF利用》

    0x00 前言 最近刷题的时候多次遇到HTTP请求走私相关的题目,但之前都没怎么接触到相关的知识点,只是在GKCTF2021--hackme中使用到了 CVE-2019-20372(Nginx< ...

  4. mmdetection源码阅读

    2021-11-23号更新 mmdetection中的hook函数 参考: 重难点总结: # step1: 根据官方文档,getattr(self,'name')等同于self.name # sept ...

  5. net core天马行空系列-微服务篇:全声明式http客户端feign快速接入微服务中心nacos

    1.前言 hi,大家好,我是三合,距离上一篇博客已经过去了整整两年,这两年里,博主通关了<人生>这个游戏里的两大关卡,买房和结婚.最近闲了下来,那么当然要继续写博客了,今天这篇博客的主要内 ...

  6. 技术分享 | App常见bug解析

    原文链接 功能Bug 内容显示错误 前端页面展示的内容有误. 这种错误的产生有两种可能 1.前端代码写的文案错误 2.接口返回值错误 功能错误 功能错误是在测试过程中最常见的类型之一,也就是产品的功能 ...

  7. ESXI系列问题整理以及记录——使用SSH为设备打VIB驱动包,同时提供一种对于ESXI不兼容螃蟹网卡(Realtek 瑞昱)的问题解决思路

    对于ESXI不兼容螃蟹网卡的问题,这里建议购买一张博通的低端单口千兆网卡,先使用博通网卡完成系统部署,再按照下文方法添加螃蟹网卡的VIB驱动,最后拆除博通网卡. 螃蟹网卡VIB驱动包下载地址:http ...

  8. 4.使用CFileDialog打开文件对话框,获得文件路径 -windows编程

    引言:没想到2022年还有很多工业软件公司依然使用MFC,微软也一直在更新MFC的库,这次使用MFC封装的CFileDialog类,写一个获得选定文件路径,名称,扩展名的程序. 个人技术博客(文章整理 ...

  9. JS:object

    object:对象 1.对象是拥有属性和方法的数据,也是一个变量,但值有多个,以key-value的形式. 2.对象有继承属性: 每当创建一个对象,对象里面就会有一个原型对象prototype,可以从 ...

  10. STM32液晶显示HT1621驱动原理及程序代码

    1.HT1621电路分析 HT1621为32×4即128点内存映像LCD驱动器,包含内嵌的32×4位显示RAM内存和时基发生器以及WDT看门狗定时器. HT1621驱动电路如下图所示: 图1 与单片机 ...