springMVC分析-2

springMVC的请求映射

上一次分析了一下springMVC的大致流程,这次细分一下,对请求映射进行分析。
先从DispatcherServlet中的getHandler()方法分析

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {for (HandlerMapping hm : this.handlerMappings) {if (logger.isTraceEnabled()) {logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");}HandlerExecutionChain handler = hm.getHandler(request);if (handler != null) {return handler;}}return null;
}

可以看到这是遍历所有的handlerMappings然后第一个返回不是NULL的handler既是,那handlerMappings包含了那些实现类呢?我们来看看initHandlerMappings这个方法

private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;//detectAllHandlerMappings 默认是trueif (this.detectAllHandlerMappings) {// 从ApplicationContext 里面获取HandlerMapping的实现类Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);//根据Order对HandlerMappings进行排序if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}else {try {//获取bean name是handlerMapping的HandlerMapping实现类HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);this.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}//若HandlerMappings为空,则设置默认的在DispatcherServlet同级目录下的DispatcherServlet.properties里面设置的org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterif (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");}}
}

所以若我们想使用自定义的HandlerMapping 可在springMVC的xml配置文件中加上一个HandlerMapping的实现类,若是使用的是 这个进行配置的,其默认会加载RequestMappingHandlerMapping这个实现类(具体在org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser见),而可以在web.xml中将detectAllHandlerMappings 设置为false,然后在springMVC.xml中配置一个name为handlerMapping的实现类。如下

// web.xml
<servlet><servlet-name>myweb</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:mvc.xml</param-value></init-param><!-- 不加载所有的HandlerMapping的实现类的bean --><init-param><param-name>detectAllHandlerMappings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>//mvc.xml
<bean name="handlerMapping" class="xxx具体实现类">

继续看handlerMapping是怎么根据request获取到HandlerExecutionChain这个包含拦截器、具体处理的controller的,在AbstractHandlerMapping中以下方法

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//获取具体的处理类Object handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}//根据定义的Interceptors过滤出需要执行的拦截器,聚合成HandlerExecutionChain这个执行链HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//CORS跨域请求if (CorsUtils.isCorsRequest(request)) {CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;
}

看getHandlerInternal(request) 这个方法,这个方法是个抽象方法,所以其实现在它的子类中,可以看出这个是一个模板模式,其在抽象类中定义出方法的骨架,而后某些方法交给子类实现,这个方法有两个实现类,AbstractHandlerMethodMapping,AbstractUrlHandlerMapping 这两个具体实现类,我们先看AbstractHandlerMethodMapping 这个类实现的

/*** Look up a handler method for the given request.*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {//获取请求路径String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);if (logger.isDebugEnabled()) {logger.debug("Looking up handler method for path " + lookupPath);}//开启读锁this.mappingRegistry.acquireReadLock();try {//获取handlerMethodHandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);if (logger.isDebugEnabled()) {if (handlerMethod != null) {logger.debug("Returning handler method [" + handlerMethod + "]");}else {logger.debug("Did not find handler method for [" + lookupPath + "]");}}return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);}finally {//释放锁this.mappingRegistry.releaseReadLock();}
}

从这里可以看出 其最后处理的是一个HandlerMethod类,我们来看看这个类的结构

public class HandlerMethod {private final Object bean;private final BeanFactory beanFactory;private final Class<?> beanType;private final Method method;private final Method bridgedMethod;private final MethodParameter[] parameters;private final HandlerMethod resolvedFromHandlerMethod;
}

可以看出其是一个聚合的类,里面包含了bean,method,故而其可以一个方法对应一个请求。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {List<Match> matches = new ArrayList<Match>();//根据请求路径匹配List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);if (directPathMatches != null) {addMatchingMappings(directPathMatches, matches, request);}if (matches.isEmpty()) {// No choice but to go through all mappings...addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);}if (!matches.isEmpty()) {//最长路径匹配原则Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));Collections.sort(matches, comparator);if (logger.isTraceEnabled()) {logger.trace("Found " + matches.size() + " matching mapping(s) for [" +lookupPath + "] : " + matches);}Match bestMatch = matches.get(0);if (matches.size() > 1) {if (CorsUtils.isPreFlightRequest(request)) {return PREFLIGHT_AMBIGUOUS_MATCH;}Match secondBestMatch = matches.get(1);if (comparator.compare(bestMatch, secondBestMatch) == 0) {Method m1 = bestMatch.handlerMethod.getMethod();Method m2 = secondBestMatch.handlerMethod.getMethod();throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");}}返回handlerMethodhandleMatch(bestMatch.mapping, lookupPath, request);return bestMatch.handlerMethod;}else {return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);}
}

AbstractHandlerMethodMapping 这个抽象类实现了InitializingBean接口,所以我们可以看看afterPropertiesSet()方法,其在实例化进行的初始化操作,initHandlerMethods()方法,可以看出其在初始化时,就初始化了HandlerMethod这个。

protected void initHandlerMethods() {// 获取所有的BeanString[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :getApplicationContext().getBeanNamesForType(Object.class));for (String name : beanNames) {//判断这个bean是否包含Controller,和RequestMapping这两个注解if (!name.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(name))) {//将其注册到MappingRegistrydetectHandlerMethods(name);}}//空方法handlerMethodsInitialized(getHandlerMethods());
}

转载于:https://www.cnblogs.com/myzhong2014/p/5310140.html

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

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

相关文章

简单消息协议

简单消息协议&#xff1a;定义了ROS与工业机器人之间简单的消息协议。额外的处理程序和管理器类包含用于处理有限连接的系统。这个包是ROS-Industrial计划的一部分。 简单消息协议定义了ROS驱动层与机器人控制器层通信的消息结构。该消息结构符合下列要求&#xff1a; 1、结构足…

Centos安装Vmware-Tools工具

1、打开指定的Centos虚拟机&#xff0c;点击清单-->虚拟机-->客户机-->安装/升级VMware-Tools&#xff08;<u>W</u>&#xff09;&#xff1b; 2、登录Centos会话台&#xff0c;Applications-->Systme Tools-->Terminal&#xff1b; 3、使用“su -”…

【sqlite常用操作SQL语句】

目录 1、创建一个新的数据表 2、在已有的数据表中增加一个新的字段&#xff08;列&#xff09; 3、 在已有的数据表中增加一条新的记录&#xff08;行&#xff09; 1、创建一个新的数据表 "create table user(id int(11) primary key, name varchar(20))" 含义&…

perl-基础

1、Perl 语法入门&#xff1a; 1、print 语句&#xff1a; print "Hello, world\n"; print("Hello, world\n"); 2、引号&#xff1a; Perl双引号和单引号的区别: 双引号可以正常解析一些转义字符与变量&#xff0c;而单引号无法解析会原样输出。 3、perl数…

wdk1703+vs2015编译的诡异问题

wdk1703vs2015编译的诡异问题 最近将wdk升级到1703&#xff08;10.0.15063.0&#xff09;版本&#xff0c;编译一个新建的minifiter项目居然出现了失败 提示错误为 WindowsDriver.common.targets(460,5): error MSB6004: The specified task executable location "\stampi…

centos6虚拟机复制后修改网卡

方法1&#xff1a; 使用vmware创建centos6.4虚拟机&#xff0c; 创建完成后复制该虚拟机&#xff0c; 打开复制的虚拟机发现网卡名字是eth1&#xff0c;而网卡配置文件为eth0&#xff0c;mac地址变了 这时修改网卡配置文件&#xff0c; 删除uuid&#xff0c;修改deivce为eth1&a…

【pyinstaller打包pyqt5编写的项目为exe(脱离环境可运行)】

目录 下载pyinstaller库 0、pyinstaller语句介绍 1、单个py文件打包成exe 1)只有py文件 假设只有一个py文件&#xff1a;pyinstaller -F xxx.py 加上图标&#xff1a;pyinstaller -F xxx.py -i xxx.ico 取消命令行窗口:pyinstaller -F -w xxx.py -i xxx.ico 2) 不但有py…

熔化极气体保护电弧焊简介

1概述 熔化极气体保护电弧焊&#xff08;英文简称GMAW&#xff09;是采用连续等速送进可熔化的焊丝与被焊工件之间的电弧作为热源来熔化焊丝和母材金属&#xff0c;形成熔池和焊缝的焊接方法&#xff0c;如图1所示。为了得到良好的焊缝应利用外加气体作为电弧介质并保护熔滴、熔…

python 中cPickle学习二

写入&#xff1a; import cPickle as p shoplistfile data.data shoplist [meili,[current_account,[100000,1222],basis_account,[5555555,888]],qinshan,[current_account,[1089000,12292],basis_account,[55555955,888]],jiayou,[current_account,[10000,12292],basis_acc…

4.0 多线程基础篇

本文并非最终版本&#xff0c;如有更新或更正会第一时间置顶&#xff0c;联系方式详见文末如果觉得本文内容过长&#xff0c;请前往本人 “简书”4.0-1.1 进程 概念 : 进程是指在系统中正在运行的一个应用程序 (操作系统中每一个 APP 就是一个进程)  性质 : 每个进程之间是独…

【python pandas excel操作】

目录 1、打开Excel&#xff0c;获取不同sheet的名称 2、获取不同sheet的内容 3、 获取行数以及表头 4、对某一列的信息进行筛选 5、根据列号和索引号提取一行或者一列的数据 6、其他panda对Excel的操作 摘自&#xff1a;python对excel操作获取某一列&#xff0c;某一行的值…

焊接机器人应用现状及发展趋势

据不完全统计&#xff0c;全世界在役的工业机器人中大约有将近一半的工业机器人用于各种形式的焊接加工领域&#xff0c;焊接机器人应用中最普遍的主要有两种方式&#xff0c;即点焊和电弧焊。图4所示是这两种焊接机器人在工业机器人中所占的大致比例。我们所说的焊接机器人其实…

线性期望(BUPT2015校赛.F)

将整体期望分成部分期望来做。 F. network 时间限制 3000 ms 内存限制 65536 KB题目描述 A social network is a social structure made up of a set of social actors (such as individuals or organizations) and a set of the relationships between these actors. In simp…

【pyqt5学习】——进度条progressBar

# 进度条 self.progressBar.setValue(0) # 设置进度条的最小值 self.progressBar.setMaximum(100) # 设置进度条的最大值 # 设置进度条当前值 self.progressBar.setValue((int(curindex/excelNum)*100)) 常用方法 方法值说明setRangeQProgressBar.setRange(min, Max)通过 setR…

弧焊 不同气体对焊缝的影响 100二氧化碳 15%氩气CO2混合

Ar含量提高后&#xff0c;相比原来的100%CO2成本会提高很多。 Ar的密度比CO2小&#xff0c;焊接的焊枪必须压的很低&#xff0c;如果焊接结构中有一些狭小区域&#xff0c;焊枪则无法到达。纯CO2气体保护焊&#xff0c;焊丝可伸出较长。 Ar属于惰性气体&#xff0c;焊接时…

Windows和Linux如何使用Java代码实现关闭进程

在用selenium做自动化测试时&#xff0c;由于各种不明原因&#xff0c;有时Chrome浏览器会出现假死的情况&#xff0c;也就是整个浏览器响应超时&#xff0c;本人脚本主要部署在Windows机器上&#xff0c;所以主要以Windows为主&#xff0c;浏览器为Chrome,即如下图所示 或者由…

CSS之A标签

a标签&#xff0c;超级链接 a是英语anchor锚的意思。 a标签常用的就是三个属性&#xff1a; 1 <a href"网址" title"悬停文本" target"_blank">超级链接文字</a> 页面内的锚点&#xff0c;用name属性或者id属性 1 …

【pyqt5学习】——下拉框comboBox

# 向下拉框中添加选型&#xff0c;具体为在下拉框第index1个选型设置为内容name self.comboBox.addItem(name,index1) # 将下拉框中所有的选项删除 self.comboBox.clear() # 根据索引获取当前的下拉框内容 index self.comboBox.currentIndex() text self.comboBox.itemText(i…

安装scapy遇到的问题

1. Mac平台 在mac上安装scapy可以说是困难重重&#xff0c;一来因为scapy实在有些小众和老旧&#xff0c;再加上安装说明文档都是python2.5 也没有详细说明一些安装问题。 折腾了大概三个小时之后终于解决了这个老大难。 注&#xff1a;我的环境为anaconda2.3 - python2.7.10 一…