当前位置: 首页 > news >正文

spring-web InvocableHandlerMethod 源码分析

说明

  1. 本文基于 jdk 8, spring-framework 5.2.x 编写。
  2. @author JellyfishMIX - github / blog.jellyfishmix.com
  3. LICENSE GPL-2.0

类层次

HandlerMethod

HandlerMethod,处理器的方法的封装对象。HandlerMethod 只提供了处理器的方法的基本信息,不提供调用逻辑。

InvocableHandlerMethod,继承 HandlerMethod 类,可调用的 HandlerMethod 实现类。

ServletInvocableHandlerMethod#invokeAndHandle 方法

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

核心方法,处理请求。

  1. 执行调用处理请求,设置 responseStatus。
  2. 如果 returnValue 为空,设置 ModelAndViewContainer 为请求已处理然后 return,和 @ResponseStatus 注解相关。
  3. 设置 ModelAndViewContainer 为请求未处理,通过 HandlerMethodReturnValueHandlerComposite(HandlerMethodReturnValueHandler) 处理返回值。
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {@Nullableprivate HandlerMethodReturnValueHandlerComposite returnValueHandlers;public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// 执行调用处理请求Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);// 设置 responseStatussetResponseStatus(webRequest);// 如果 returnValue 为空,设置 ModelAndViewContainer 为请求已处理然后 return,和 @ResponseStatus 注解相关if (returnValue == null) {if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {disableContentCachingIfNecessary(webRequest);mavContainer.setRequestHandled(true);return;}}else if (StringUtils.hasText(getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}// 设置 ModelAndViewContainer 为请求未处理mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers != null, "No return value handlers");try {// 通过 HandlerMethodReturnValueHandlerComposite(HandlerMethodReturnValueHandler) 处理返回值this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);}catch (Exception ex) {if (logger.isTraceEnabled()) {logger.trace(formatErrorForReturnValue(returnValue), ex);}throw ex;}}
}

ServletInvocableHandlerMethod#setResponseStatus 方法

org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#setResponseStatus

调用 setResponseStatus(ServletWebRequest webRequest) 设置响应的状态码。

  1. 获得 status,和 @ResponseStatus 注解相关。
  2. 设置响应的状态码。有 reason,则设置 status + reason。无 reason,仅设置 status。
  3. RedirectView 相关。
	private void setResponseStatus(ServletWebRequest webRequest) throws IOException {// 获得 status,和 @ResponseStatus 注解相关HttpStatus status = getResponseStatus();if (status == null) {return;}// 设置响应的状态码HttpServletResponse response = webRequest.getResponse();if (response != null) {String reason = getResponseStatusReason();// 有 reason,则设置 status + reasonif (StringUtils.hasText(reason)) {response.sendError(status.value(), reason);}else {// 无 reason,仅设置 statusresponse.setStatus(status.value());}}// To be picked up by RedirectView// RedirectView 相关webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);}

InvocableHandlerMethod

InvocableHandlerMethod#invokeForRequest 方法 – 执行调用处理请求

org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest

执行调用处理请求。

	@Nullablepublic 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);}

InvocableHandlerMethod#getMethodArgumentValues 方法 – 解析参数

org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues

  1. 获得方法的参数。
  2. 遍历方法参数,将参数解析成对应的类型。
    1. 获得当前遍历的 MethodParameter 对象,给它设置 parameterNameDiscoverer。
    2. 从 providedArgs 中获得参数。如果获得到,则进入下一个参数的解析,默认情况 providedArgs 不会传参。
    3. 判断 resolvers 是否支持当前的参数解析。
    4. 执行参数解析,解析成功后进入下一个参数的解析。
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {// 获得方法的参数MethodParameter[] parameters = getMethodParameters();// 无参,返回空数组if (ObjectUtils.isEmpty(parameters)) {return EMPTY_ARGS;}// 遍历方法参数,将参数解析成对应的类型Object[] args = new Object[parameters.length];for (int i = 0; i < parameters.length; i++) {// 获得当前遍历的 MethodParameter 对象,给它设置 parameterNameDiscovererMethodParameter parameter = parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);// 从 providedArgs 中获得参数。如果获得到,则进入下一个参数的解析,默认情况 providedArgs 不会传参。args[i] = findProvidedArgument(parameter, providedArgs);if (args[i] != null) {continue;}// 判断 resolvers 是否支持当前的参数解析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 ex) {// Leave stack trace for later, exception may actually be resolved and handled...if (logger.isDebugEnabled()) {String exMsg = ex.getMessage();if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {logger.debug(formatArgumentError(parameter, exMsg));}}throw ex;}}return args;}

InvocableHandlerMethod#doInvoke 方法

org.springframework.web.method.support.InvocableHandlerMethod#doInvoke

  1. 设置方法为可访问。
  2. 通过反射执行方法调用。BridgedMethod 基于泛型安全为了和 jdk 1.5 之前的字节码兼容,无需关注 BridgedMethod。
	@Nullableprotected Object doInvoke(Object... args) throws Exception {// 设置方法为可访问ReflectionUtils.makeAccessible(getBridgedMethod());try {// 通过反射执行方法调用。BridgedMethod 基于泛型安全为了和 jdk 1.5 之前的字节码兼容,无需关注 BridgedMethodreturn getBridgedMethod().invoke(getBean(), args);}catch (IllegalArgumentException ex) {assertTargetBean(getBridgedMethod(), getBean(), args);String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");throw new IllegalStateException(formatInvokeError(text, args), ex);}catch (InvocationTargetException ex) {// Unwrap for HandlerExceptionResolvers ...Throwable targetException = ex.getTargetException();if (targetException instanceof RuntimeException) {throw (RuntimeException) targetException;}else if (targetException instanceof Error) {throw (Error) targetException;}else if (targetException instanceof Exception) {throw (Exception) targetException;}else {throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);}}}

后言

  1. 本文可以看到很重要的两个组件 HandlerMethodArgumentResolver 用于获取请求参数,HandlerMethodReturnValueHandler 用于处理返回值,后续分析。

相关文章:

spring-web InvocableHandlerMethod 源码分析

说明 本文基于 jdk 8, spring-framework 5.2.x 编写。author JellyfishMIX - github / blog.jellyfishmix.comLICENSE GPL-2.0 类层次 HandlerMethod&#xff0c;处理器的方法的封装对象。HandlerMethod 只提供了处理器的方法的基本信息&#xff0c;不提供调用逻辑。 Invoca…...

一分钟了解微信公众号服务器配置自动回复

1、建一个web服务工程 2、开放任意一个接口&#xff0c; 比如 /aaa/bbb/ccc 把接口路径配置在这里&#xff0c;ip为公网ip或域名&#xff0c;其他的参数默认&#xff0c;对入门选手没啥用 3、该接口允许get和post两种方式访问&#xff0c;接口需要对于访问方式编写两套逻辑…...

打印不同的图形-课后程序(JAVA基础案例教程-黑马程序员编著-第四章-课后作业)

【案例4-1】打印不同的图形 记得 关注&#xff0c;收藏&#xff0c;评论哦&#xff0c;作者将持续更新。。。。 【案例介绍】 案例描述 本案例要求编写一个程序&#xff0c;可以根据用户要求在控制台打印出不同的图形。例如&#xff0c;用户自定义半径的圆形和用户自定义边长的…...

14. QT_OPenGL中引入顶点着色器和片段着色器

1. 说明: 着色器是OPenGL中非常重要的一部分&#xff0c;在有了模型后&#xff0c;如果未给模型添加着色器&#xff0c;那么渲染效果会折扣很多。着色器中使用到的语言是GLSL(OPenGL Shader Language)&#xff0c;可以通过这篇文章GLSL基本语法进行了解。 效果展示&#xff1a…...

ecaozzz

2. 图形报表ECharts 2.1 ECharts简介 ECharts缩写来自Enterprise Charts&#xff0c;商业级数据图表&#xff0c;是百度的一个开源的使用JavaScript实现的数据可视化工具&#xff0c;可以流畅的运行在 PC 和移动设备上&#xff0c;兼容当前绝大部分浏览器&#xff08;IE8/9/10/…...

应用部署初探:6个保障安全的最佳实践

在之前的文章中&#xff0c;我们了解了应用部署的阶段以及常见的部署模式&#xff0c;包括微服务架构的应用应该如何部署等基本内容。本篇文章将介绍如何安全地部署应用程序。 安全是软件开发生命周期&#xff08;SDLC&#xff09;中的关键部分&#xff0c;同时也需要成为 S…...

转转测试环境docker化实践

测试环境对于任何一个软件公司来讲&#xff0c;都是核心基础组件之一。转转的测试环境伴随着转转的发展也从单一的几套环境发展成现在的任意的docker动态环境docker稳定环境环境体系。期间环境系统不断的演进&#xff0c;去适应转转集群扩张、新业务的扩展&#xff0c;走了一些…...

linux 之 ps命令介绍

哈喽&#xff0c;大家好&#xff0c;我是有勇气的牛排&#xff08;全网同名&#xff09;&#x1f42e; 有问题的小伙伴欢迎在文末评论&#xff0c;点赞、收藏是对我最大的支持&#xff01;&#xff01;&#xff01;。 前言 如过想实现对进程监控&#xff0c;就需要使用到ps命…...

Server端的Actor,分工非常的明确,但是只将Actor作为一部手机来用,真的合适吗?

这是一篇介绍PowerJob&#xff0c;Server端Actor的文章&#xff0c;如果感兴趣可以请点个关注&#xff0c;大家互相交流一下吧。 server端一共有两个Actor&#xff0c;一个是处理worker传过来的信息&#xff0c;一个是server之间的信息传递。 处理Worker的Actor叫做WorkerRequ…...

2023年美赛C题 预测Wordle结果Predicting Wordle Results这题太简单了吧

2023年美赛C题 预测Wordle结果Predicting Wordle Results 更新时间&#xff1a;2023-2-17 11:30 1 题目 2023年MCM 问题C:预测Wordle结果![在这里插入图片描述](https://img-blog.csdnimg.cn/e059d917333e497e90ca082605869e3c.png#pic_center) Wordle是纽约时报目前每天提…...

UE4 渲染学习笔记(未完)

原文链接&#xff1a;虚幻4渲染管线入门 - 知乎 从原文摘抄一下&#xff1a; 渲染框架 1&#xff0c;一套是传统的以RHICmdList为核心构建RenderPass&#xff0c;从RHICmdList.BeginRenderPass(...)开始&#xff0c;以RHICmdList.EndRenderPass()结束的框架。 2.一套是以新的Gr…...

Ajax?阿贾克斯?

一、Ajax简介 AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 AJAX 不是新的编程语言&#xff0c;而是一种使用现有标准的创新方法。 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网…...

项目质量要怎么保持? 如何借助系统软件进行管理

对于任何项目型的企业总是很关心项目成本的话题&#xff0c;但不知从什么时候开始&#xff0c;高质量等于高成本成了各个企业的一种潜意识。 如果交付的项目产品不符合质量标准&#xff0c;即使企业使用最好的项目管理工具或者每个里程碑都达到并在预算范围内完成项目&#xf…...

没有接口文档的怎样进行接口测试

前言&#xff1a; 在进行接口测试之前&#xff0c;一般开发会提供接口文档&#xff0c;给出一些接口参数和必要熟悉&#xff0c;便于我们编写接口脚本。但如果没有提供接口开发文档的请求下&#xff0c;我们该如何编写接口测试脚本呢&#xff1f;在编写测试脚本前要做哪些必要…...

Unity—游戏设计模式+GC

每日一句&#xff1a;"少年一贯快马扬帆 道阻且长不转弯 要盛大要绚烂要哗然 要用理想的泰坦尼克去撞现实的冰川 要当烧赤壁的风而非借箭的草船 要为一片海就肯翻万山。" 目录 状态模式&#xff1a; 外观模式 组合模式&#xff0c; 单例模式 命令模式 观察者模…...

【刷题笔记】--二分查找binarysearch

当给一个有序的数组&#xff0c;在其中查找某个数&#xff0c;可以考虑用二分查找。 题目1&#xff1a; 二分查找的思路&#xff1a; 设置left和right指针分别指向要查找的区间。mid指针指向这个区间的中间。比较mid指针所指的数与target。 如果mid所指的数小于target&…...

Python版本的常见模板(二) 数论(一)

文章目录前言质数相关质数判断求约数求取区间质数埃氏筛法线性筛法分解质因数欧拉欧拉函数求取单个数线性筛法求取欧拉定理求逆元快速幂/幂取模欧几里得算法求最小公约数拓展欧几里得算法求解同余方程前言 本文主要是提供Python版本的常见的一些与数论相关的模板&#xff0c;例…...

SQL快速上手(知识点总结+训练资料)

文章目录一 SQL训练资料二 SQL知识点总结1.SQL语句的执行顺序2.窗口函数3.字符串处理函数模糊查询三 SQL题目的总结一 SQL训练资料 牛客SQL题目 猴子数据分析题目 关注的公众号 猴子数据分析 二 SQL知识点总结 1.SQL语句的执行顺序 每一个子句产生的中间结果供接下来的子句…...

无需经验的steam搬砖,每天操作1小时,轻松创业赚钱!

我作为一个95后社畜&#xff0c;就喜欢倒腾各种赚钱的事情&#xff0c;8年老韭菜告诉你&#xff0c;副业创收一点都不难&#xff0c;难就难在是否找对项目&#xff0c;俗话说方向不对&#xff0c;努力白费&#xff01; 什么做苦力、技能、直播卖货&#xff0c;电商等等对比我这…...

如何创建你的公司的FAQ页面?

很多企业考虑为公司搭建一个“常见问题”页面&#xff0c;作为帮助客户回答关于产品和服务的常见问题的一种方式。 FAQ页面和登录/销售页面不同&#xff0c;没有展现出直接的投资回报&#xff0c;但是为团队节省了其他成本&#xff0c;据了解&#xff0c;高达67%的客户相比于跟…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...