HandlerMapping之RequestMappingHandlerMapping作用详解

  • 前言
  • RequestMappingHandlerMapping
    • @RequestMapping
    • @RequestMapping的注册
  • 总结

前言

上回我们知道HandlerMapping是用来寻找Handler的,并不与Handler的类型或者实现绑定,而是根据需要定义的。

那么为什么要单独给@RequestMapping实现一个HandlerMapping?这次咱们就来专门看看这个RequestMappingHandlerMapping。

RequestMappingHandlerMapping

名字来源

因为RequestMappingHandlerMapping是专门为@RequestMapping而生的,因此他的名字是这样来的:@RequestMapping的HandlerMapping了。

为什么不叫MethodHandlerMapping呢?

主要还是Handler是一个逻辑概念,MethodHandler了只是对目标方法进行了封装,并不是真正处理请求的。

真正处理请求的是我们@RequestMapping的方法。取个名字都给你讲道理。

@RequestMapping

在解答文章开头的问题前,我们先看看@RequestMapping

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {/*** 处理器的名字,支持类级别和方法级别,多个路径用#分割*/String name() default "";/*** 匹配请求路径*/@AliasFor("path")String[] value() default {};/*** 匹配请求路径*/@AliasFor("value")String[] path() default {};/*** Http请求方法:可选GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE*/RequestMethod[] method() default {};/*** 匹配指定的地址栏参数*/String[] params() default {};/*** 匹配特定的header*/String[] headers() default {};/*** 匹配特定的Content-Type*/String[] consumes() default {};/*** 匹配特定的Accept*/String[] produces() default {};
}

发现了吗,各位?他除了能根据URI匹配,还能根据请求头、请求方法、甚至是请求参数来匹配!

上回说的基于URL的两种HandlerMapping都不能满足他,因此必须推出一个更加强大、可扩展性更强的HandlerMapping——RequestMappingHandlerMapping

那么问题来了:

  • @RequestMapping是在什么如何被解析的呢?
    • 我们很容易想到的就是,遍历容器中所有的对象,检查是否存在@Controller注解。存在,那就是控制器。然后接着遍历所有声明的public方法,检查是否存在@RequestMapping方法。这样,我们就找到了处理器方法。
  • @RequestMapping是在什么时候被解析的呢?
    • 本着“谁使用,谁解析”的原则,他自然是被RequestMappingHandlerMapping解析的。而又因为@RequestMapping的寻找可太费功夫,不可能在提供映射服务时再来解析,只能是初始化时进行解析。因此实现InitializingBean进行初始化,是个选择。

没错,实际上,SpringMVC跟你想的一样。在InitializingBean的afterPropertiesSet方法中,完成了以3下件事:

  1. 寻找@Controller的bean,并找到所有的@RequestMapping方法
  2. 解析@RequestMapping封装成RequestMappingInfo
  3. 将以上解析到的信息进行注册。

信息包括:

信息描述
@Controller/@RequestMapping对象反射调用目标方法时,需要的target对象
RequestMappingInfo由@RequestMapping解析而来
@RequestMapping的方法注册时,注册器会将Method与handler对象一起封装成HandlerMethod进行注册。便于后面适配器调用。

@RequestMapping的注册

前面的解析@RequestMapping到RequestMappingInfo,可以省略,比较简单。但是@RequestMapping的注册没办法省略。因为如果搞不清楚他是怎么注册的,也就没办法理解他是怎么寻找目标处理器的。

为了支撑@RequestMapping多样化的匹配条件,不能再像前面两款HanderMapping一样,简单粗暴的使用Map了。在 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping 的内部定义了内部类,专门用来做注册中心,管理映射关系。

/*** Mapping注册中心,可以理解为办事处*/class MappingRegistry {/*** T是匹配条件的对象。MappingRegistration是注册的信息,可以理解为你要做事情。* 对于RequestMappingHandlerMapping,T就是RequestMappingInfo* MappingRegistration包括信息:RequestMappingInfo、HandlerMethod、directPaths、mappingName、corsConfig*/private final Map<T, MappingRegistration<T>> registry = new HashMap<>();/*** Map<path, RequestMappingInfo>*/private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();/*** Map<mappingName, List<HandlerMethod>>*/private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();}

 

从他的属性,我们可以分析得到如下信息:

  1. 直接通过请求路径来查找处理器时,需要经过pathLookup中转registry,最后拿到MappingRegistration才到达HandlerMethod.
  2. 直接通过mappingName则可以直接找到HandlerMethod. 不过这个是Spring为了支持 <%@ taglib uri="//www.springframework.org/tags" prefix="s" %> 而提供的。跟我们平时使用没多大关系。

但是各位观众老爷,pathLookup找到的是一个,而mappingName能找到多个,这是咋回事?误会啊,pathLookup的value可不是简单的一个元素,而是多个!他是MultiValueMap,不是我们经常看到的地摊货HashMap。他可以一个key对应多个value。

但是为什么会有多个呢?或者说为什么需要保存多个呢? 因为一个Handler可以处理多个请求,如果由多个Handler都能处理某一个请求的时候怎么办呢?况且SpringMVC还支持通配符匹配。umm…这一幕有点似曾相识,我们的nginx做路由转发的时候,不是也有类似的问题吗?这意味着在查找Handler的时候,我们还需要找到最佳的匹配。例如,/*相较于/hello,那肯定是/hello更精确,更合适啦。你看,多严谨!

总结

由于@RequestMapping支持灵活的请求匹配条件,而不只是简单的路径,只能开发出RequestMappingHandlerMapping进行支持。

RequestMappingHandlerMapping是通过InitializingBean进行初始化的,在这里完成@RequestMappingHandlerMapping的扫描和解析,以及注册。

HandlerMethod是在注册时进行封装的。获取Handler时,拿到的Handler就是HandlerMethod。

后面的适配器适配的,也是他。

RequestMappingHandlerMapping使用了InitializingBean做初始化,但是当我们自己在做初始化的时候,尤其是使用多种初始化方式的时候,应当要注意Spring的调用顺序,否则有可能发生NPE,或者获取不到目标属性的情况。

例如:同时在ApplicationContextAware、InitializingBean、@PostConstruct进行初始化。 为此,给大家找了官方的bean的生命周期

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/467216.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《UE5_C++多人TPS完整教程》学习笔记12 ——《P13 加入游戏会话(Joining The Sessions)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P13 加入游戏会话&#xff08;Joining The Session&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是…

操作系统基础:IO管理概述【上】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;OS从基础到进阶 &#x1f3c6;&#x1f3c6;本文完整PDF源文件请翻阅至文章底部下载。&#x1f3c6;&#x1f3c6; &#x1f3ae;1 I/O设备的基本概念与分类&#x1f52b;1.1 总览&#x…

最新Burp Suite入门讲解

Burp Suite的安装 Burp Suite是一款集成化的渗透测试工具&#xff0c;包含了很多功能&#xff0c;可以帮助我们高效地完成对Web应用程序的渗透测试和安全检测。 Burp Suite由Java语言编写&#xff0c;Java自身的跨平台性使我们能更方便地学习和使用这款软件。不像其他自动化测…

HTML 超文本标记语言

超文本标记语言 HTML 在一个客户程序主窗口上显示出的万维网文档称为页面 (page)。 页面制作的标准语言&#xff1a;HTML。 超文本标记语言 HTML (HyperText Markup Language) 是一种制作万维网页面的标准语言&#xff0c;它消除了不同计算机之间信息交流的障碍&#xff0c…

P1164 小A点菜题解

题目 uim拿到了uoi的镭牌后&#xff0c;立刻拉着基友小A到了一家餐馆&#xff0c;很低端的那种。uim指着墙上的价目表&#xff08;太低级了没有菜单&#xff09;&#xff0c;说&#xff1a;“随便点”。 不过uim由于买了一些书&#xff0c;口袋里只剩M元(M≤10000)。 餐馆虽…

【Java程序设计】【C00269】基于Springboot的漫画网站(有论文)

基于Springboot的漫画网站&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的漫画网站 本系统分为系统功能模块、管理员功能模块、以及用户功能模块。 系统功能模块&#xff1a;在系统首页可以查看首页、漫画投稿、…

Ubuntu20.04更新Cmake版本详解

最近在跑一个融合惯导定位的slam框架ins_eskf_kitti&#xff0c;在框架的安装过程中&#xff0c;需要对从GitHub上克隆下来的glog进行编译。其命令如下&#xff1a; glog&#xff1a; git clone https://github.com/google/glog.git cd glog mkdir build cd build cmake .. m…

【实战】一、Jest 前端自动化测试框架基础入门(中) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(二)

文章目录 一、Jest 前端自动化测试框架基础入门5.Jest 中的匹配器toBe 匹配器toEqual匹配器toBeNull匹配器toBeUndefined匹配器和toBeDefined匹配器toBeTruthy匹配器toBeFalsy匹配器数字相关的匹配器字符串相关的匹配器数组相关的匹配器异常情况的匹配器 6.Jest 命令行工具的使…

Spring Boot 笔记 012 创建接口_添加文章分类

1.1.1 实体类添加校验 package com.geji.pojo;import jakarta.validation.constraints.NotEmpty; import lombok.Data;import java.time.LocalDateTime;Data public class Category {private Integer id;//主键IDNotEmptyprivate String categoryName;//分类名称NotEmptypriva…

Google刚刚推出了图神经网络Tensorflow-GNN

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

jsp课程教学管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 课程教学管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

Linux network namespace 访问外网以及多命名空间通信(经典容器组网 veth pair + bridge 模式认知)

写在前面 整理K8s网络相关笔记博文内容涉及 Linux network namespace 访问外网方案 Demo实际上也就是 经典容器组网 veth pair bridge 模式理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已…