Spring 请求方法的调用原理(Controller)和请求参数的获取的原理
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、请求参数注解处理原理
原理图
- 先得到请求的request
在获取可以处理请求的方法的Mapping映射器
DispatcherServlet中的
doDispatch方法
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
判断每个参数带有注解是哪个,是否存在相应的解析器
寻找合适的处理适配器
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)和请求参数的获取的原理的更多相关文章
- 关于ASP.NET中WEBAPI中POST请求中FromBody修饰的string类型的参数服务器端获取不到值FromBody空值的简单解决方法
其实解决办法很简单,就是POST请求的时候,来自实体的参数,content-type:application/x-www-form-urlencoded情况下,是默认按照键值对来解析的,比如param ...
- SpringBoot中Post请求提交富文本数据量过大参数无法获取的问题
yml增加配置 # 开发环境配置 server: tomcat: max-http-form-post-size: -1
- Spring MVC中基于注解的 Controller
终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响 ...
- springMVC学习总结(二)路径映射和请求方法限定
springMVC学习总结(二)路径映射和请求方法限定 一.路径映射 无参数的访问路径 对springmvc项目的访问路径,是由根路径和子路径组成:在注解式开发中,根路径标注在类名之上,子路径标注在方 ...
- HTTP请求方法
HTTP请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, ...
- HTTP状态码、请求方法、响应头信息
HTTP状态码 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求.当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应 ...
- HTTP请求方法
HTTP请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法. HTTP1.1新增了五种请求方法:OPTIONS, ...
- HTTP-Runoob:HTTP请求方法
ylbtech-HTTP-Runoob:HTTP请求方法 1.返回顶部 1. HTTP请求方法 根据HTTP标准,HTTP请求可以使用多种请求方法. HTTP1.0定义了三种请求方法: GET, PO ...
- HTTP协议中request报文请求方法和状态响应码
一个HTTP请求报文由4部分组成: 请求行(request line) 请求头部(header) 空行 请求数据 下图给出了请求报文的一般格式: 请求行中包括了请求方法,常见的请求方法有: GET:从 ...
随机推荐
- 好客租房22-react组件的两种创建方式(类组件)
2.2使用类创建组件 类组件:使用ES6的class创建的组件 约定1:类组件必须以大写字母开头 约定2:类组件应该继承react.component父类 从中可以使用父类的方法和属性 约定3:组件必 ...
- 安装Squid到CentOS(YUM)
运行环境 系统版本:CentOS Linux release 7.3.1611 (Core) 软件版本:无 硬件要求:无 安装过程 1.关闭防火墙和SeLinux [root@localhost ~] ...
- 协议层安全相关《http请求走私与CTF利用》
0x00 前言 最近刷题的时候多次遇到HTTP请求走私相关的题目,但之前都没怎么接触到相关的知识点,只是在GKCTF2021--hackme中使用到了 CVE-2019-20372(Nginx< ...
- mmdetection源码阅读
2021-11-23号更新 mmdetection中的hook函数 参考: 重难点总结: # step1: 根据官方文档,getattr(self,'name')等同于self.name # sept ...
- net core天马行空系列-微服务篇:全声明式http客户端feign快速接入微服务中心nacos
1.前言 hi,大家好,我是三合,距离上一篇博客已经过去了整整两年,这两年里,博主通关了<人生>这个游戏里的两大关卡,买房和结婚.最近闲了下来,那么当然要继续写博客了,今天这篇博客的主要内 ...
- 技术分享 | App常见bug解析
原文链接 功能Bug 内容显示错误 前端页面展示的内容有误. 这种错误的产生有两种可能 1.前端代码写的文案错误 2.接口返回值错误 功能错误 功能错误是在测试过程中最常见的类型之一,也就是产品的功能 ...
- ESXI系列问题整理以及记录——使用SSH为设备打VIB驱动包,同时提供一种对于ESXI不兼容螃蟹网卡(Realtek 瑞昱)的问题解决思路
对于ESXI不兼容螃蟹网卡的问题,这里建议购买一张博通的低端单口千兆网卡,先使用博通网卡完成系统部署,再按照下文方法添加螃蟹网卡的VIB驱动,最后拆除博通网卡. 螃蟹网卡VIB驱动包下载地址:http ...
- 4.使用CFileDialog打开文件对话框,获得文件路径 -windows编程
引言:没想到2022年还有很多工业软件公司依然使用MFC,微软也一直在更新MFC的库,这次使用MFC封装的CFileDialog类,写一个获得选定文件路径,名称,扩展名的程序. 个人技术博客(文章整理 ...
- JS:object
object:对象 1.对象是拥有属性和方法的数据,也是一个变量,但值有多个,以key-value的形式. 2.对象有继承属性: 每当创建一个对象,对象里面就会有一个原型对象prototype,可以从 ...
- STM32液晶显示HT1621驱动原理及程序代码
1.HT1621电路分析 HT1621为32×4即128点内存映像LCD驱动器,包含内嵌的32×4位显示RAM内存和时基发生器以及WDT看门狗定时器. HT1621驱动电路如下图所示: 图1 与单片机 ...