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

Spring MVC 启动之 HandlerMapping

        在上一篇文章中,我们介绍了 Spring MVC 的启动流程,接下来我们将发分多个篇章详细介绍流程中的重点步骤

d.png

        今天我们从 HandlerMapping 开始分析,HandlerMapping 是框架中的一个非常重要的组件。它的作用是将URL请求映射到合适的处理程序(Handler)上,这样就能够实现控制器与页面之间的交互。在 Spring MVC 中,有多种不同的 HandlerMapping 实现,本文将对这些实现的作用和源码原理进行详细介绍。

作用

在 Spring MVC 框架中,HandlerMapping 是一个非常重要的组件,它的作用是将URL请求映射到相应的处理程序上。具体来说,HandlerMapping 会根据URL请求的路径、请求参数等信息,确定需要执行哪个处理程序,并将该处理程序返回给 DispatcherServlet。然后 DispatcherServlet 再将请求分配给相应的处理程序,处理程序处理完请求后,将结果返回给 DispatcherServlet,DispatcherServlet 再将结果返回给客户端。

c.png

HandlerMapping的实现

        Spring MVC 框架中有多种不同的 HandlerMapping 实现,每种实现都有不同的作用和使用场景。下面将逐一介绍这些实现。

BeanNameUrlHandlerMapping

        BeanNameUrlHandlerMapping 是 Spring MVC 框架中最简单的 HandlerMapping 实现,它的作用是将 URL 请求的路径映射到 Bean 的名称上。具体来说,当请求的路径与一个 Bean 的名称匹配时,BeanNameUrlHandlerMapping 会将该请求映射到对应的 Bean 上。

例如:

  1. 假设有一个名为 “/hello” 的请求
  2. 我们可以在 Spring 配置文件中定义一个名为 “helloController” 的 Bean
  3. 然后使用 BeanNameUrlHandlerMapping 将 “/hello” 请求映射到该 Bean 上

这样,当客户端发送 “/hello” 请求时,DispatcherServlet 就会将该请求分配给 “helloController” 处理。

BeanNameUrlHandlerMapping 的源码比较简单,它的核心代码如下所示:

public class BeanNameUrlHandlerMapping extends AbstractUrlHandlerMapping {protected Object getHandlerInternal(HttpServletRequest request) throws Exception {String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);return obtainHandler(lookupPath, request);}
}

        从代码中可以看出,BeanNameUrlHandlerMapping 实现了 AbstractUrlHandlerMapping 接口,并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的 URL 路径查找相应的处理程序

SimpleUrlHandlerMapping

SimpleUrlHandlerMapping 是 Spring MVC 框架中另一种常用的 HandlerMapping 实现,它的作用是将 URL 请求的路径映射到处理程序上。与 BeanNameUrlHandlerMapping 不同的是,SimpleUrlHandlerMapping 可以将一个URL请求映射到多个处理程序上

例如:

  1. 假设有两个请求 “/hello” 和 “/world”
  2. 我们可以使用 SimpleUrlHandlerMapping 将这两个请求分别映射到不同的处理程序上。具体来说,我们可以在 Spring 配置文件中定义多个 Bean,并分别为它们设置不同的URL路径。
  3. 然后使用 SimpleUrlHandlerMapping 将这些URL路径与相应的处理程序进行映射。

这样,当客户端发送一个请求时,SimpleUrlHandlerMapping 就会根据请求的URL路径查找相应的处理程序,并将请求分配给该处理程序处理。

SimpleUrlHandlerMapping 的源码也比较简单,它的核心代码如下所示:

public class SimpleUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {protected Object getHandlerInternal(HttpServletRequest request) throws Exception {String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);Object handler = lookupHandler(lookupPath, request);if (handler == null) {handler = getDefaultHandler();}return handler;}
}

        从代码中可以看出,SimpleUrlHandlerMapping 同样实现了 AbstractUrlHandlerMapping 接口(在 AbstractDetectingUrlHandlerMapping 中继承),并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的URL路径查找相应的处理程序。

ControllerClassNameHandlerMapping

        ControllerClassNameHandlerMapping 是Spring MVC 框架中一种比较特殊的 HandlerMapping 实现,它的作用是将URL请求的路径映射到 Controller 类名上。具体来说,ControllerClassNameHandlerMapping 会根据请求的URL路径查找对应的 Controller 类名,并将该类返回给 DispatcherServlet,然后 DispatcherServlet 再将请求分配给该 Controller 类处理。

例如:

  1. 假设有一个名为 “/hello” 的请求
  2. 我们可以定义一个名为 HelloController的Controller 类
  3. 使用 ControllerClassNameHandlerMapping 将 “/hello” 请求映射到该类上。

这样,当客户端发送 “/hello” 请求时,ControllerClassNameHandlerMapping 就会将该请求映射到 HelloController 处理。

ControllerClassNameHandlerMapping 的源码也比较简单,它的核心代码如下所示:

public class ControllerClassNameHandlerMapping extends AbstractControllerUrlHandlerMapping {protected Object getHandlerInternal(HttpServletRequest request) throws Exception {String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);String controllerClassName = getClassNameForUrlPath(lookupPath);return obtainApplicationContext().getBean(controllerClassName);}
}

        从代码中可以看出,ControllerClassNameHandlerMapping 同样实现了 AbstractUrlHandlerMapping 接口,并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的URL路径查找相应的 Controller 类名,并将该类返回给 DispatcherServlet。

DefaultAnnotationHandlerMapping

        DefaultAnnotationHandlerMapping 是Spring MVC 框架中另一种比较常用的 HandlerMapping实 现,它的作用是将 URL 请求的路径映射到标注了 @RequestMapping 注解的方法上

        具体来说,DefaultAnnotationHandlerMapping 会扫描应用程序中所有标注了 @RequestMapping 注解的方法,并将这些方法与相应的URL路径进行映射。

        然后当客户端发送一个请求时,DefaultAnnotationHandlerMapping 就会根据请求的URL路径查找相应的处理程序,并将该处理程序返回给 DispatcherServlet,然后 DispatcherServlet 再将请求分配给该处理程序处理。

例如:

  1. 假设有一个名为 “/hello” 的请求
  2. 我们可以在 Controller 类的某个方法上标注 @RequestMapping 注解
  3. 将该方法与 “/hello” 请求进行映射。

这样,当客户端发送 “/hello” 请求时,DefaultAnnotationHandlerMapping 就会将该请求映射到该方法上,然后将该方法返回给 DispatcherServlet 处理。

DefaultAnnotationHandlerMapping 的源码比较复杂,因为它需要扫描应用程序中所有标注了 @RequestMapping 注解的方法。其核心代码如下所示:

public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandlerMapping implements BeanFactoryAware, InitializingBean {private final List<RequestMappingInfoHandlerMapping> handlerMappings = new ArrayList<>();protected Object getHandlerInternal(HttpServletRequest request) throws Exception {for (RequestMappingInfoHandlerMapping hm : this.handlerMappings) {HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;}public void afterPropertiesSet() throws Exception {initHandlerMethods();}protected void initHandlerMethods() {detectHandlerMethods();if (logger.isInfoEnabled()) {logger.info("Mapped " + this.handlerMethods.size() + " request handler methods");}}protected void detectHandlerMethods() {...}
}

        从代码中可以看出,DefaultAnnotationHandlerMapping 同样实现了 AbstractUrlHandlerMapping 接口,并重写了其中的 getHandlerInternal 方法。该方法的作用是根据请求的 URL 路径查找相应的处理程序。

        与其他 HandlerMapping 不同的是,DefaultAnnotationHandlerMapping 还实现了 BeanFactoryAware和InitializingBean 接口,以便在初始化时扫描应用程序中所有标注了 @RequestMapping 注解的方法。

        具体来说,它会调用 detectHandlerMethods 方法,对应用程序中所有标注了 @RequestMapping 注解的方法进行扫描,并将这些方法与相应的URL路径进行映射。

总结

        在 Spring MVC 框架中,HandlerMapping 用于将URL请求的路径映射到相应的处理程序上。框架中提供了多种不同的 HandlerMapping 实现,包括 BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping、ControllerClassNameHandlerMapping 和 DefaultAnnotationHandlerMapping 等。不同的HandlerMapping 实现方式适用于不同的应用场景。

  • BeanNameUrlHandlerMapping 是最简单的HandlerMapping实现,它将 URL 请求的路径直接映射到 Bean 的名称上。
  • SimpleUrlHandlerMapping 则将 URL 请求的路径与相应的处理程序进行映射。
  • ControllerClassNameHandlerMapping 将 URL 请求的路径映射到 Controller 类名上。
  • DefaultAnnotationHandlerMapping 则将 URL 请求的路径映射到标注了 @RequestMapping 注解的方法上。

无论是哪种 HandlerMapping 实现方式,它们都遵循相同的流程来处理请求。具体来说,它们的流程如下:

客户端发送请求到DispatcherServlet。

  1. DispatcherServlet根据请求的URL路径选择相应的HandlerMapping。
  2. HandlerMapping将请求的URL路径与相应的处理程序进行映射。
  3. HandlerMapping返回相应的处理程序。
  4. DispatcherServlet将请求交给相应的处理程序进行处理。
  5. 处理程序进行业务逻辑的处理,并返回相应的结果。
  6. DispatcherServlet将处理程序的结果进行封装,并返回给客户端。

相关文章:

Spring MVC 启动之 HandlerMapping

在上一篇文章中&#xff0c;我们介绍了 Spring MVC 的启动流程&#xff0c;接下来我们将发分多个篇章详细介绍流程中的重点步骤 今天我们从 HandlerMapping 开始分析&#xff0c;HandlerMapping 是框架中的一个非常重要的组件。它的作用是将URL请求映射到合适的处理程序&#x…...

基于YOLOv5的停车位检测系统(清新UI+深度学习+训练数据集)

摘要&#xff1a;基于YOLOv5的停车位检测系统用于露天停车场车位检测&#xff0c;应用深度学习技术检测停车位是否占用&#xff0c;以辅助停车场对车位进行智能化管理。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集以及PyQt的UI界面。博文提供了完整的Py…...

【Linux系统编程】5.vim基本操作命令

目录 跳转到指定行 命令模式 末行模式 跳转行首 跳转行尾 自动格式化代码 大括号、中括号、小括号对应 光标移至行首 光标移至行尾 删除单个字符 删除一个单词 删除光标至行尾 删除光标至行首 替换单个字符 删除指定区域 删除指定1行 删除指定多行 复制一行 …...

主流机器学习平台调研与对比分析

梗概 本报告主要调研目前主流的机器学习平台&#xff0c;包括但不限于Amazon的Sage maker&#xff0c;Alibaba的PAI&#xff0c;Baidu的PaddlePaddle。对产品的定位、功能、实践、定价四个方面进行详细解析&#xff0c;并通过标杆对比分析提出一套机器学习平台评价体系&#x…...

作业帮基于明道云开展的硬件业务数字化建设

今天由我代表作业帮来介绍公司在低代码平台应用的一些经验和心得。我今天分享的内容包含两部分&#xff0c;一个是作业帮硬件的介绍&#xff0c;另一个是基于明道云的系统能力建设&#xff0c;也是我们自己总结的经验&#xff0c;希望能给大家带来一些启发。 一、关于作业帮 …...

位图及布隆过滤器的模拟实现与面试题

位图 模拟实现 namespace yyq {template<size_t N>class bitset{public:bitset(){_bits.resize(N / 8 1, 0);//_bits.resize((N >> 3) 1, 0);}void set(size_t x)//将某位做标记{size_t i x / 8; //第几个char对象size_t j x % 8; //这个char对象的第几个比特…...

在 Python 中将天数添加到日期

使用 datetime 模块中的 timedelta() 方法将天数添加到日期中&#xff0c;例如 result_1 date_1 timedelta(days3)。 timedelta 方法可以传递天数参数并将指定的天数添加到日期。 from datetime import datetime, date, timedelta# ✅ 将天数添加到日期 my_str 09-24-2023 …...

vue3知识点

一、vue3带来了什么&#xff1f; 1.性能的提升 打包大小减少41% 初次渲染快55%&#xff0c;更新渲染快133% 内存减少54% 2.源码的升级 使用Proxy代替defineProperty实现响应式 重写虚拟DOM的实现和Tree-shaking 3.拥抱TypeScript Vue3可以更好的支持TypeScript 4.新的特性 4.1.…...

一行代码生成Tableau可视化图表

今天给大家介绍一个十分好用的Python模块&#xff0c;用来给数据集做一个初步的探索性数据分析(EDA)&#xff0c;有着类似Tableau的可视化界面&#xff0c;我们通过对于字段的拖拽就可以实现想要的可视化图表&#xff0c;使用起来十分的简单且容易上手&#xff0c;学习成本低&a…...

链表——删除元素或插入元素(头插法及尾插法)

目录 链表的结点由一个结构体构成 判断链表是否为空 键盘输入链表中的数据 输出链表中的数据 返回链表的元素个数 清空链表 返回指定位置的元素值 查找数据所在位置 删除链表的元素 插入元素 建立无头结点的单链表 建立有头结点的单链表&#xff08;头插法&#xff…...

oracle容器的使用

oracle容器的使用 1.下载oracle容器 1.1拉取容器 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g拉取国内镜像&#xff0c;该镜像大小为2.99G&#xff0c;已经集成了oracle环境&#xff0c;拉取完可以直接用&#xff0c;推荐使用这款oracle镜像 1.2查看…...

基于springboot会员制医疗预约服务管理信息系统演示【附项目源码】

基于springboot会员制医疗预约服务管理信息系统演示开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea M…...

GoogleAdsense国内加载慢怎么解决?

一淘模板 56admin.com 发现GoogleAdsense&#xff08;谷歌广告联盟&#xff09;国内加载慢拖网站速度怎么解决&#xff1f;GoogleAdsense是谷歌旗下的站长广告联盟系统&#xff0c;如果站长没有好的变现渠道&#xff0c;挂谷歌联盟是最好的选择&#xff08;日积月累&#xff09…...

【MySQL专题】03、性能优化之读写分离(MaxScale)

在我们了解了MySQL的主从复制的性能优化之后&#xff0c;紧接着《【MySQL专题】02、性能优化之主从复制》中&#xff0c;我们提及的读写分离&#xff0c;来进行读操作和写操作分散到不同的服务器结构中&#xff0c;同时希望对多个从服务器能提供负载均衡&#xff0c;读写分离和…...

Redis7高级之BigKey(二)

1.MoreKey案例 往redis里面插入大量测试数据key 生成100W条redis批量设置kv的语句保存在redisTest.txt for((i1;i<100*10000;i)); do echo "set k$i v$i" >> /tmp/redisTest.txt ;done; # 生成100W条redis批量设置kv的语句(keykn,valuevn)写入到/tmp目录下的…...

flex弹性盒子

概念 弹性盒子是一种用于按行或者按列布局的一维布局方法&#xff0c;元素可以膨胀以填充额外的空间&#xff0c;缩小以适应更小的空间 以下属性是给父元素添加的 1.flex-direction --改变轴的方向 row 默认值 默认沿着x轴排版(横向从左到右排列&#xff08;左对齐&#xff…...

[Java Web]Cookie | 一文详细介绍会话跟踪技术中的Cookie

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Java Web 目录Cookie1、工作原理2、如何使用2.1、发送Cookie2.2、获取Cookie3、Cookie的存活时间4、中文错误Coo…...

这可能是2023最全的Java面试八股文,共计1658页,Java技术手册的天花板

前两天有个小伙伴在后台留言&#xff0c;最近的面试越来越难了&#xff0c;尤其是技术面&#xff0c;考察得越来越细&#xff0c;越来越底层&#xff0c;庆幸的是最终顺利找到了工作。 一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识 比如果这样的问题…...

字节流及存放本地文件上传和下载文件

前言 之前的文章有写过 vuespringboot使用文件流实现文件下载 实现如何通过 D:\file\文件名.文件格式的形式进行下载文件 但是它对于很多业务场景相对适用性不是很广泛。 以及 elementUI加springboot实现上传excel文件给后端并读取excel 也只能是通过elementui的元素类型进行…...

【翻译】下一步:Go 泛型

原文地址&#xff1a; The Next Step for Generics - The Go Blog https://blog.golang.org/generics-next-step 介绍 自从我们上次写下关于在Go中加入泛型的可能性的文章以来&#xff0c;已经快一年了。现在是该更新的时候了。 设计的更新 我们一直在继续完善泛型设计草案。…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

Linux基础开发工具——vim工具

文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...

FTXUI::Dom 模块

DOM 模块定义了分层的 FTXUI::Element 树&#xff0c;可用于构建复杂的终端界面&#xff0c;支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...