Spring MVC 源码分析之 DispatcherServlet#getHandlerAdapter 方法
前言:
前面我们分析了 Spring MVC 的工作流程源码,其核心是 DispatcherServlet#doDispatch 方法,我们前面分析了获取 Handler 的方法 DispatcherServlet#getHandler 方法,本篇我们重点分析一下获取当前请求的适配器 HandlerAdapter 的实现原理,具体方法入口是 DispatcherServlet#getHandlerAdapter。
Spring MVC 知识传送门:
详解 Spring MVC(Spring MVC 简介)
Spring MVC 初始化源码分析
Spring MVC 工作流程源码分析
Spring MVC 源码分析之 DispatcherServlet#getHandler 方法
** DispatcherServlet#getHandlerAdapter方法源码分析**
DispatcherServlet#getHandlerAdapter方法就是从 handlerAdapters 中查询匹配当前请求的 Handler,只要找到了就不在循环直接返回,我们我们重点关注adapter.supports(handler) 这行代码,这里实际调用的是接口的抽象类 AbstractHandlerMapping 中的 getHandler 方法,下面接着分析。
//org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {this.handlerAdapters 为空判断 DispatcherServlet 初始化时注册的 handlerAdaptersif (this.handlerAdapters != null) {//迭代遍历Iterator var2 = this.handlerAdapters.iterator();while(var2.hasNext()) {HandlerAdapter adapter = (HandlerAdapter)var2.next();//找到匹配当前 handler的 adapterif (adapter.supports(handler)) {//找到就返回return adapter;}}}//如果最后都没找到 抛出异常throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
AbstractHandlerMethodAdapter#supports 方法源码分析
AbstractHandlerMethodAdapter#supports 没有什么复杂的逻辑,只是判断了 handler 是否是 HandlerMethod 类型,至于 AbstractHandlerMethodAdapter#supportsInternal 方法它默认返回 fasle,也就是说只要 handler 是 HandlerMethod 类型,就算匹配成功。
//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
public final boolean supports(Object handler) {//handler 是否是 HandlerMethod 类型 // this.supportsInternal 抽象方法 由子类实现 RequestMappingHandlerAdapter#supportsInternal 默认返回 truereturn handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler);
}
//org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supportsInternal
protected abstract boolean supportsInternal(HandlerMethod var1);//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#supportsInternal
protected boolean supportsInternal(HandlerMethod handlerMethod) {return true;
}
HandlerExecutionChain#applyPreHandle 方法源码分析
HandlerExecutionChain#applyPreHandle 方法的主要左右就是调用拦截器的 preHandle 方法,如果有某个拦截器的 preHandle 方法返回 false,就会逆向调用返回 true 的拦截器的 triggerAfterCompletion 方法。
//org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {//获取所有拦截器数组HandlerInterceptor[] interceptors = this.getInterceptors();//为空判断if (!ObjectUtils.isEmpty(interceptors)) {//循环调用 拦截器的 preHandle 方法//this.interceptorIndex 记录当前拦截器的位置for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {HandlerInterceptor interceptor = interceptors[i];//判断拦截器的 preHandle 方法返回值if (!interceptor.preHandle(request, response, this.handler)) {//拦截器 preHandle 方法返回 false 则反向调用返回 true 的那些拦截器的 afterCompletion 方法this.triggerAfterCompletion(request, response, (Exception)null);//返回 falsereturn false;}}}return true;
}//org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {//获取所有拦截器HandlerInterceptor[] interceptors = this.getInterceptors();//为空判断if (!ObjectUtils.isEmpty(interceptors)) {//反向遍历 这里是的 interceptorIndex 上面记录了的 --i 就是反向遍历for(int i = this.interceptorIndex; i >= 0; --i) {HandlerInterceptor interceptor = interceptors[i];try {//调用拦截器的 afterCompletion 方法interceptor.afterCompletion(request, response, this.handler, ex);} catch (Throwable var8) {logger.error("HandlerInterceptor.afterCompletion threw exception", var8);}}}}
HandlerExecutionChain#applyPostHandle 方法源码分析
拦截器的 preHandle 方法调用完成后,就会调用 handle 方法处理具体请求(后面分析),handle 方法调用完成后就会调用拦截器的 applyPreHandle 方法, HandlerExecutionChain#applyPreHandle 方法的主要左右就是逆向调用拦截器的 postHandle 方法。
//org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {//获取所有拦截器HandlerInterceptor[] interceptors = this.getInterceptors();//为空判断if (!ObjectUtils.isEmpty(interceptors)) {for(int i = interceptors.length - 1; i >= 0; --i) {//逆向调用拦截器的 postHandle 方法HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}}
本篇主要分析了 Spring MVC 工作流程中比较简单的几个关键点,HandlerAdapter 的适配过程、拦截器的前置后置处理等,这些在流程中比较简单的环节就放在一起分析了,希望可以帮助到有需要的朋友。
欢迎提出建议及对错误的地方指出纠正。
相关文章:
Spring MVC 源码分析之 DispatcherServlet#getHandlerAdapter 方法
前言: 前面我们分析了 Spring MVC 的工作流程源码,其核心是 DispatcherServlet#doDispatch 方法,我们前面分析了获取 Handler 的方法 DispatcherServlet#getHandler 方法,本篇我们重点分析一下获取当前请求的适配器 HandlerAdapt…...
假设检验学习笔记
1. 假设检验的基本概念 1.1. 原假设(零假设) 对总体的分布所作的假设用表示,并称为原假设或零假设 在总体分布类型已知的情况下,仅仅涉及总体分布中未知参数的统计假设,称为参数假设 在总体分布类型未知的情况下&#…...
vue3 watch学习
watch的侦听数据源类型 watch的第一个参数为侦听数据源,有4种"数据源": ref(包括计算属性) reactive(响应式对象) getter函数 多个数据源组成的数组。 //ref const xref(0)//单个ref watch(x,(newX)>{console.…...
推荐的Pytest插件
推荐的Pytest插件 Pytest的插件生态系统非常丰富,以下是一些特别推荐的Pytest插件: pytest-sugar 这个插件改进了Pytest的默认输出,添加了进度条,并立即显示失败的测试。它不需要额外配置,只需安装即可享受更漂亮、更…...
C语言 | Leetcode C语言题解之第124题二叉树中的最大路径和
题目: 题解: /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ int max; int dfs(struct TreeNode* root){if(!root) return 0;int left dfs(root->left…...
Linux综合实践(Ubuntu)
目录 一、配置任务 1.1 配置该服务器的软件源为中科大软件源 1.2 安装相关软件openssh-server和vim 1.3 设置双网卡,网卡1为NAT模式,网卡2为桥接模式(桥接模式下,使用静态ip,该网卡数据跟实验室主机网络设置相似,除…...
C++面试题其二
19. STL中unordered_map和map的区别 unordered_map 和 map 都是C标准库中的关联容器,但它们在实现和性能方面有显著区别: 底层实现:map 是基于红黑树实现的有序关联容器,而 unordered_map 是基于哈希表实现的无序关联容器。元素…...
系统架构设计师【第9章】: 软件可靠性基础知识 (核心总结)
文章目录 9.1 软件可靠性基本概念9.1.1 软件可靠性定义9.1.2 软件可靠性的定量描述9.1.3 可靠性目标9.1.4 可靠性测试的意义9.1.5 广义的可靠性测试与狭义的可靠性测试 9.2 软件可靠性建模9.2.1 影响软件可靠性的因素9.2.2 软件可靠性的建模方法9.2.3 软件的可靠性模…...
x264 参考帧管理原理:i_poc_type 变量
x264 参考帧管理 x264 是一个开源的 H.264 视频编码软件,它提供了许多高级特性,包括对参考帧的高效管理。参考帧管理是视频编码中的一个重要部分,它涉及到如何存储、更新和使用已经编码的帧以提高编码效率。 x264 参考帧管理的一些关键点总结如下: 参考帧的初始化和重排序:…...
高级Web Lab2
高级Web Lab2 12 1 按照“Lab 2 基础学习文档”文档完成实验步骤 实验截图: 2 添加了Web3D场景选择按钮,可以选择目标课程或者学习房间。...
Linux网络-使用Tcp协议进行网络通信并通过网络接口实现远端翻译
文章目录 Tcp协议Tcp协议常见API接口1. int socket(int domain, int type, int protocol);2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);struct sockaddr 3. int listen(int socket, int backlog);4. int accept(int socket, struct socka…...
实时数据传输:Django 与 MQTT 的完美结合
文章目录 准备工作创建 Django 项目与应用设置 MQTT 服务器编写 Django 视图编写前端模板发布 MQTT 消息运行 Django 项目 在当今互联网应用中,实时数据传输已经成为许多项目的核心需求。无论是社交媒体平台、在线游戏、金融交易还是物联网设备,都需要及…...
创建Django项目及应用
1 创建Project 1个Project可以对应多个app django-admin startproject myproject 2 创建App python manage.py startapp app01 INSTALLED_APPS [# ...app01,app02,# ... ] 如果要让这个应用在项目中起作用,需要在项目的 settings.py 文件的 INSTALLED_APPS 配置…...
Flutter课程分享 -(系统课程 基础 -> 进阶 -> 实战 仿京东商城)
前言 在移动应用开发的世界中,Flutter 作为一款由 Google 推出的开源 UI 软件开发工具包,正迅速赢得开发者们的青睐。其跨平台、高性能、丰富的组件库以及易于学习的特性,使得 Flutter 成为许多开发者的不二选择。然而,对于初学者…...
IDEA 中导入脚手架后该如何处理?
MySQL数据库创建啥的,没啥要说的!自行配置即可! 1.pom.xml文件,右键,add Maven Project …………(将其添加为Maven)【下述截图没有add Maven Project 是因为目前已经是Maven了!&…...
thinkphp6 queue队列的maxTries自定义
前景需求:在我们用队列的时候发现maxtries的个数时255次,这个太影响其他队列任务 我目前使用的thinkphp版本是6.1 第一部定义一个新的类 CustomDataBase(我用的mysql数据库存放的队列) 重写__make 和createPlainPayload方法 …...
【PHP项目实战训练】——laravel框架的实战项目中可以做模板的增删查改功能(2)
👨💻个人主页:开发者-曼亿点 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 曼亿点 原创 👨💻 收录于专栏:…...
Kotlin 对象
文章目录 对象表达式(匿名对象)对象的声明 对象表达式(匿名对象) 在 Kotlin 中可以使用object {}声明一个匿名的对象,我们无需声明这个对象的类: fun main() {val any object {fun greet() print("…...
力扣 142题 环形链表Ⅱ 记录
题目描述 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内…...
乐观锁 or 悲观锁 你怎么选?
你有没有听过这样一句话:悲观者正确,乐观者成功。那么今天我来分享下什么是乐观锁和悲观锁。 乐观锁和悲观锁有什么区别,它们什么场景会用 乐观锁 乐观锁基于这样的假设:多个事务在同一时间对同一数据对象进行操作的可能性很…...
通过Taotoken用量看板直观掌握团队API消耗情况
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 通过Taotoken用量看板直观掌握团队API消耗情况 对于依赖大模型API进行开发的团队而言,清晰、准确地掌握资源消耗情况是…...
GD32C103RBT6 DAC 驱动库详细解析
本文基于GD32C10x 官方固件库 V1.0.0,深度解析 DAC 外设驱动库gd32c10x_dac.c,包含驱动概述、核心函数详解、可直接运行的工程例程,适合 GD32 单片机开发入门与实战。 一、DAC 外设概述 1.1 GD32C10x DAC 基本特性 双通道 12 位数字 / 模拟转换器(DAC0、DAC1) 输出电压范…...
终极指南:如何快速解决iPhone在Windows上的USB网络共享问题
终极指南:如何快速解决iPhone在Windows上的USB网络共享问题 【免费下载链接】Apple-Mobile-Drivers-Installer Powershell script to easily install Apple USB and Mobile Device Ethernet (USB Tethering) drivers on Windows! 项目地址: https://gitcode.com/g…...
终极指南:如何为yt-dlp-gui扩展新的视频平台支持
终极指南:如何为yt-dlp-gui扩展新的视频平台支持 【免费下载链接】yt-dlp-gui Windows GUI for yt-dlp 项目地址: https://gitcode.com/gh_mirrors/yt/yt-dlp-gui 你是否曾遇到过想要下载某个小众视频平台的视频,却发现yt-dlp-gui无法识别链接&am…...
告别在线安装卡顿:手把手教你离线部署Vitis 2021.2到Ubuntu 20.04(含77G包处理技巧)
高效离线部署Vitis 2021.2:Ubuntu 20.04全流程实战指南 对于从事FPGA开发的工程师而言,稳定可靠的开发环境搭建是项目成功的第一步。当网络条件受限或需要批量部署时,离线安装方式往往成为刚需。本文将深入解析如何在Ubuntu 20.04系统上完成V…...
基于RAG与本地LLM的智能代码库管理工具部署与优化指南
1. 项目概述:一个为开发者打造的智能代码库管理工具最近在整理自己过去几年的项目代码时,我遇到了一个几乎所有开发者都会头疼的问题:代码库越来越多,但想快速找到某个特定功能的实现、或者想复用一段之前写过的优质代码时&#x…...
如何在5分钟内用Python获取同花顺问财金融数据?
如何在5分钟内用Python获取同花顺问财金融数据? 【免费下载链接】pywencai 获取同花顺问财数据 项目地址: https://gitcode.com/gh_mirrors/py/pywencai 你是否曾经为了获取金融数据而花费大量时间编写爬虫,却总是面临反爬机制和接口变动的困扰&a…...
AI VTuber技术栈全解析:从Live2D到GPT-SoVITS的实战搭建指南
1. 项目概述:为什么我们需要一份AI VTuber的“Awesome”清单? 如果你最近在GitHub、B站或者一些技术社区里逛过,大概率会看到一个词反复出现: AI VTuber 。它不再是科幻电影里的概念,而是正在快速渗透到直播、内容创…...
对抗测试框架:用字节码增强与混沌工程提升系统韧性
1. 项目概述:一个对抗测试的“剧院”最近在开源社区里,我注意到一个名字挺有意思的项目,叫nanami7777777/anti-test-theater。乍一看,这个标题有点让人摸不着头脑——“反测试剧院”?测试和剧院能扯上什么关系…...
Panda-AGI开源框架:构建具备长期记忆与规划能力的AI智能体
1. 项目概述:当“熊猫”遇上AGI,一个开源智能体的新范式最近在开源社区里,一个名为sinaptik-ai/panda-agi的项目引起了我的注意。光看名字就很有意思,“Panda”和“AGI”(Artificial General Intelligence,…...
