SpringMVC核心组件之HandlerMapping详解

文章目录

  • 前言
  • 一、AbstractHandlerMapping抽象类
    • initApplicationContext
    • getHandler
  • 二、MatchableHandlerMapping类
  • 二、AbstractUrlHandlerMapping类


前言

当一个web请求到来时,DispatcherServlet负责接收请求并响应结果。DispatcherServlet首先需要找到当前请求对应的handler(处理器)来处理请求,流程如下图所示。
在这里插入图片描述

DispatcherServlet中有一个成员变量叫做handlerMappings,是一个HandlerMapping的集合,当请求到来时,DispatcherServlet遍历handlerMappings中的每一个HandlerMapping以获取对应的handler。上述步骤发生在DispatcherServlet的doDispatch() 方法中,部分源码如下所示。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 根据请求获取handlermappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// ......}}}

handler的获取由DispatcherServlet的getHandler() 方法完成,下面再看一下getHandler() 具体做了什么事情。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;
}

handlerMappings是HandlerMapping的集合,因此getHandler() 主要实现遍历每一个HandlerMapping并根据请求获取对应的handler。

HandlerMapping 叫做处理器映射器, 请求的处理器匹配器,负责为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器们(interceptors)。

  • handler 处理器可以将其理解成 HandlerMethod 对象(例如我们使用最多的 @RequestMapping 注解所标注的方法会解析成该对象),包含了方法的所有信息,通过该对象能够执行该方法
  • HandlerInterceptor 拦截器对处理请求进行增强处理,可用于在执行方法前、成功执行方法后、处理完成后进行一些逻辑处理 HandlerMapping 接口:
public interface HandlerMapping {String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";@DeprecatedString LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath";String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";default boolean usesPathPatterns() {return false;}@NullableHandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

可以看到,除了一堆声明的常量外,其实就一个需要实现的方法 getHandler,该方法的返回值就是我们所了解到的 HandlerExecutionChain。

HandlerMapping 的继承关系如下:
在这里插入图片描述
在HandlerMapping类的层级结构图中,MatchableHandlerMapping接口是一个从Spring4.3.1开始新增的一个接口,用来判断给定的请求是否符合请求条件。
除此之外,HandlerMapping接口有一个公共的抽象类AbstractHandlerMapping,所有子孙实现类都需要继承。
该抽象类下有三个直接子类,分别是AbstractHandlerMethodMapping、AbstractUrlHandlerMapping和RouterFunctionMapping
其中RouterFunctionMapping是从Spring MVC5.2开始引入的,主要用于WebFlux处理中;
而另外两个直接实现类,代表了两大类实现方式:

  • AbstractUrlHandlerMapping表示根据url获取对应的handler;
  • AbstractHandlerMethodMapping表示基于方法的映射方式,这也是我们在实际工作中使用较多的一种方式。

一、AbstractHandlerMapping抽象类

AbstractHandlerMapping类图如下:
在这里插入图片描述
AbstractHandlerMapping,实现 HandlerMapping、Ordered、BeanNameAware 接口,继承 WebApplicationObjectSupport 抽象类,实现了“为请求找到合适的 HandlerExecutionChain 处理器执行链”对应的的骨架逻辑,而暴露 getHandlerInternal(HttpServletRequest request) 抽象方法,交由子类实现。

initApplicationContext

@Override
@Override
protected void initApplicationContext() throws BeansException {// <1> 空实现,交给子类实现,用于注册自定义的拦截器到 interceptors 中,目前暂无子类实现extendInterceptors(this.interceptors);// <2> 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中detectMappedInterceptors(this.adaptedInterceptors);// <3> 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中initInterceptors();
}

getHandler

getHandler(HttpServletRequest request) 方法,获得请求对应的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器们(interceptors),方法如下:

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// <1> 获得处理器(HandlerMethod 或者 HandlerExecutionChain),该方法是抽象方法,由子类实现Object handler = getHandlerInternal(request);// <2> 获得不到,则使用默认处理器if (handler == null) {handler = getDefaultHandler();}// <3> 还是获得不到,则返回 nullif (handler == null) {return null;}// Bean name or resolved handler?// <4> 如果找到的处理器是 String 类型,则从 Spring 容器中找到对应的 Bean 作为处理器if (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}// <5> 创建 HandlerExecutionChain 对象(包含处理器和拦截器)HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);if (logger.isTraceEnabled()) {logger.trace("Mapped to " + handler);}else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {logger.debug("Mapped to " + executionChain.getHandler());}if (CorsUtils.isCorsRequest(request)) {CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;
}

二、MatchableHandlerMapping类

MatchableHandlerMapping,定义了“判断请求和指定 pattern 路径是否匹配”的方法。

public interface MatchableHandlerMapping extends HandlerMapping {//返回{@code HandlerMapping}的解析器,如果配置了,则使用预先解析的模式。default PathPatternParser getPatternParser() {return null;}RequestMatchResult match(HttpServletRequest request, String pattern);}

RequestMatchResult 类,判断请求和指定 pattern 路径是否匹配时,返回的匹配结果。

二、AbstractUrlHandlerMapping类

AbstractUrlHandlerMapping 主要用来通过URL进行匹配。思路如下:把URL与Handler的对应关系存到一个Map中,然后在getHandlerInternal方法中,根据URL去获取对应的Handler对象,在AbstractUrlHandlerMapping抽象类中,主要实现了根据url获取对应Handler的方法,如何初始化这个Map对象,交由子类进行实现。

主要属性

//根处理器,处理“/”的处理器
@Nullable
private Object rootHandler;
//是否匹配尾部的“/”,比如:如果设置为ture,则"/users"的匹配模式,也会匹配"/users/"
private boolean useTrailingSlashMatch = false;
//设置是否延迟加载,只对单例的处理器有效
private boolean lazyInitHandlers = false;
//保存request和Handler对应关系的变量
private final Map<String, Object> handlerMap = new LinkedHashMap<>();

getHandlerInternal方法
实现了父类中的抽象方法,根据request获取对应的handler

@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {//获取lookupPath,并保存到request属性中String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);request.setAttribute(LOOKUP_PATH, lookupPath);//获取lookupPath 对应的handlerObject handler = lookupHandler(lookupPath, request);if (handler == null) {//如果没有获取到对应的handler,则进行下面处理// We need to care for the default handler directly, since we need to// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.Object rawHandler = null;if ("/".equals(lookupPath)) {//如果时根路径,则获取根处理器,即属性rootHandler中保存的处理器rawHandler = getRootHandler();}if (rawHandler == null) {//获取默认处理器,在父类中定义,即父类中的defaultHandler属性rawHandler = getDefaultHandler();}if (rawHandler != null) {// Bean name or resolved handler?if (rawHandler instanceof String) {//获取对应的Bean实例String handlerName = (String) rawHandler;rawHandler = obtainApplicationContext().getBean(handlerName);}//模板方法,校验处理器,交由子类实现或扩展validateHandler(rawHandler, request);//根据原始的handler构建实际的handler,主要实现构建HandlerExecutionChain对象,并在request添加对应的参数,后续在详细分析handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);}}return handler;
}

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

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

相关文章

普通人也能创业!轻资产短视频带货项目,引领普通人实现创业梦想

在这个信息爆炸的时代&#xff0c;创业似乎成为了越来越多人的梦想。然而&#xff0c;传统的创业模式 keJ0277 往往伴随着高昂的资金投入和复杂的管理流程&#xff0c;让许多普通人望而却步。然而&#xff0c;现在有一种轻资产短视频带货项目正在悄然兴起&#xff0c;它以其低…

2024做安全测试必须要知道的几种方法!

前言 安全性测试(Security Testing)是指有关验证应用程序的安全等级和识别潜在安全性缺陷的过程&#xff0c;其主要目的是查找软件自身程序设计中存在的安全隐患&#xff0c;并检查应用程序对非法侵入的防范能力&#xff0c;安全指标不同&#xff0c;测试策略也不同。 但安全…

『Apisix安全篇』快速掌握APISIX Basic-Auth插件高效使用

&#x1f4e3;读完这篇文章里你能收获到 &#x1f468;‍&#x1f4bb; 学习如何快速安装并配置APISIX Basic-Auth插件&#xff0c;为您的API安全保驾护航。&#x1f6e0;️ 文章详细介绍了如何创建带有basic-auth配置的Consumer&#xff0c;以及如何在Route中启用该插件。&am…

微信自主创建表单投票小程序源码系统 带充值刷礼物功能 附带源代码以及完整的安装部署教程

系统概述 本小程序实现的核心功能包括&#xff1a;用户注册登录、表单提交投票、查看投票结果、在线充值以及赠送礼物等。其中&#xff0c;投票表单可以根据实际需求进行自定义设置&#xff0c;满足不同类型的调查或评选活动。同时&#xff0c;通过引入第三方支付接口&#xf…

Django Celery 的配置及使用---最详细教程

Django Celery 的配置及使用 Redis提供队列消息功能 一、安装redis 系统版本&#xff1a;Ubuntu 20.041、获取最新软件包 sudo apt update sudo apt install redis-server2、安装完成后&#xff0c;Redis服务器会自动启动。查看redis是否启动成功 sudo systemctl status …

LLM大模型多模态面试题(二)

1. 介绍transformer算法 Transformer本身是一个典型的encoder-decoder模型&#xff0c;Encoder端和Decoder端均有6个Block&#xff0c;Encoder端的Block包括两个模块&#xff0c;多头self-attention模块以及一个前馈神经网络模块&#xff1b;Decoder端的Block包括三个模块&…

uniapp 实现下拉刷新 下滑更新

效果图 在app或者小程序中向下滑动 会出现刷新数据 ,而上拉到底 需要更新数据 功能实现 主要俩种方式 依赖生命周期 在page.json中开启 page.json "style" : {"navigationBarTitleText" : "小小练习","backgroundTextStyle": &qu…

狙击策略专用术语以及含义,WeTrade3秒讲解

想必各位交易高手对狙击策略不会陌生吧!但你想必不知道狙击策略的开发者为了推广狙击策略&#xff0c;在狙击策略基础的经典技术分析理论引入了自己的术语。今天WeTrade众汇和各位投资者继续了解狙击策略专用术语以及含义。 一.BL 银行级别(BL)是前一日线收盘的级别。时间是格…

微信小程序开发中怎么配置SSL证书?

在微信小程序开发中&#xff0c;配置SSL证书主要用于实现HTTPS请求&#xff0c;以保证数据传输的安全性。以下是配置SSL证书的基本步骤&#xff1a; 一、获取SSL证书 首先&#xff0c;你需要获取一个有效的SSL证书。SSL证书可以被广泛信任的证书颁发机构申请&#xff0c;如Jo…

rocketmq的顺序消息开发注意事项

1. 参考消息重试&#xff0c;要对 MaxReconsumeTimes进行设置。之前就是因为没有进行设置&#xff0c;导致了队头阻塞问题。 rokcetmq和kafka一样&#xff0c;当顺序消息写入的多个队列中后&#xff0c;如果是顺序消息&#xff0c;当前的队列的队头一直消费失败的时候&#x…

JVM运行时内存:本地方法接口与本地方法栈

文章目录 1. 什么是本地方法&#xff1f;2. 为什么要使用Native Method&#xff1f;3. 本地方法现状 运行时内存整体结构如下图所示: 1. 什么是本地方法&#xff1f; 简单地讲&#xff0c;一个Native Method就是一个Java调用非 Java 代码的接口。一个Native Method是这样一个 …

【Linux】linux | 配置系统日志 | 安全日志 | 操作日志 | 登录日志

一、诉求 1、linux服务器开启日志功能&#xff0c;并记录10个月的登录 二、操作 1、进入目录 cd /etc 2、编辑配置 vi logrotate.conf 3、复制配置 /var/log/wtmp {monthlycreate 0664 root utmpminsize 1Mrotate 10 }/var/log/btmp {missingokmonthlycreate 0600 root …

vue2人力资源项目9权限管理

页面搭建 <template><div class"container"><div class"app-container"><el-button size"mini" type"primary">添加权限</el-button><el-table-column label"名称" /><el-table-co…

Spring Boot代码案例(计算器、登录、留言板)

文章目录 一、计算器二、登录2.1 判断账号密码是否正确2.2 根据不同的用户作出不同反应 三、留言板3.1 提交数据3.2 展示所有数据 四、Lombok 工具包4.1 场景介绍4.2 如何使用 五、Edit Starters插件六、项目如何Debug七、项目命名规范 一、计算器 导入前端文件后端代码&#…

AI Agent是什么?未来如何发展

AI Agnt是什么 AI代理&#xff08;AI Agent&#xff09;是指一种利用人工智能技术来执行特定任务或解决特定问题的自主软件程序。这些代理通过学习和模拟人类行为或特定领域的知识&#xff0c;能够在无需人为干预的情况下完成复杂的任务。AI代理广泛应用于多个领域&#xff0c…

SSM【Spring SpringMVC Mybatis】—— SpringMVC

目录 1、初识SpringMVC 1.1 SpringMVC概述 1.2 SpringMVC处理请求原理简图 2、SpringMVC搭建框架 2.1 搭建SpringMVC框架 3、RequestMapping详解 3.1 RequestMapping注解位置 3.2 RequestMapping注解属性 3.3 RequestMapping支持Ant 风格的路径&#xff08;了解&#…

【Linux玩物志】Linux环境开发基本工具使用(1)——vim

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; Linux开发工具 首先我们要知道vim是什么&#xff1f; vi&#xff08;Visual Editor&#xff09;是由美国程序员比尔乌尔曼&#xff08;Bill Joy&#xff09;于1976年开发的&#xff0c;最初是为了在Unix系统上进行文本编…

技术前沿 |【大模型LLaMA:技术原理、优势特点及应用前景探讨】

大模型LLaMA&#xff1a;技术原理、优势特点及应用前景探讨 一、引言二、大模型LLaMA的基本介绍三、大模型LLaMA的优势特点五、结论与展望 一、引言 随着人工智能技术的飞速发展&#xff0c;大模型已成为推动这一领域进步的重要力量。近年来&#xff0c;大模型LLaMA以其卓越的…

我和jetson-Nano的故事(11)——在ros中编译usb_cam

在jetson nano中编译旧版本的usb_cam 1. 问题背景1.1 jetson nano的软件环境版本 2.问题现象3.问题原因及解决办法 1. 问题背景 最近给jetson nano重装了系统之后&#xff0c;在编译今年人工智能ROS小车比赛用的工程包的时候&#xff0c;遇到一个问题迟迟没有解决&#xff0c;…

惠海 H4112 同步整流30V降压芯片IC 24V转12V5V3.3V3.5A方案EN使能控制

惠海H4112同步整流30V降压芯片IC是一款DCDC电源管理芯片&#xff0c;它具备精确恒压和恒流的同步降压能力&#xff0c;适用于多种应用场景&#xff0c;如汽车充电器、照明灯、便携式设备供电电源和电池充电器等。 输出电压与电流调整&#xff1a; H4112支持输出电压在2.5V到2…