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

springMVC分析-2相关推荐

  1. springMVC分析-1

    MVC 作为一个MVC框架,必须回答一下几个问题 请求映射到控制器 请求数据进行绑定 视图渲染 而spring mvc是如何解决这几个问题的呢? 首先,从DispatcherServlet这个入口开始 ...

  2. spring和springMVC配置文件中的扫描包如何配置

    我的项目大概文件路径: 然后进入主题: spring的配置文件名称为applicationContext.xml springMVC的配置文件名称为dispatcherServlet-servlet. ...

  3. SSM框架学习文档以及SSM整合(附Github地址=含SSM学习时的实例代码)

    SSM框架学习 软件架构: 基于流行SSM框架:Spring+SpringMVC+Mybatis 项目配置: 使用Maven进行项目jar导入 ​ 使用Git进行版本控制,并将每次编写的代码上传到Gi ...

  4. spring注解驱动开发-10 Servlet3.0

    Spring AOP实现 前言 servlet3.0简介 ServletContainerInitializer shared libraries(共享库) / runtimes pluggabili ...

  5. 尚硅谷Spring注解开发学习笔记

    文章目录 前言 1.课程安排 1.1.容器 1.2.扩展原理 1.3.Web 2.配置文件开发 2.1.导入Spring-context依赖包 2.2.编写Spring配置文件 2.3.编写Perso ...

  6. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  7. SpringMVC启动分析

    以下分析基于JDK1.8 启动的第一步是执行监听器,这里web.xml中配置了一个监听器org.springframework.web.context.ContextLoaderListener 接下 ...

  8. SpringMVC学习(一)———— springmvc框架原理分析和简单入门程序

    一.什么是springmvc? 我们知道三层架构的思想,并且如果你知道ssh的话,就会更加透彻的理解这个思想,struts2在web层,spring在中间控制,hibernate在dao层与数据库打交 ...

  9. SpringMVC之源码分析--ViewResolver(四)

    概述 本章继续学习ViewResolver另一个实现类ContentNegotiatingViewResolver解析器,该类的主要作用是根据同一请求的某些策略,选择对应的View进行渲染.可以把Co ...

最新文章

  1. 【Visual C++】游戏开发笔记二十七 Direct3D 11入门级知识介绍
  2. BroadcastReceiver应用详解(一)
  3. [NOI2011]兔兔与蛋蛋游戏 二分图博弈
  4. mysqlbinlog查看 binlog日志报错mysqlbinlog: unknown variable 'default-character-set=utf8mb4'
  5. 解决启动Biee控制台乱码问题
  6. 一文教你使用java开发一款推箱子游戏
  7. python爬取b站评论_python高效之爬了B站再爬微博
  8. php 页面缓存的做法,使用php进行页面缓存
  9. 超级计算器 android,超级计算器解方程
  10. python实现报表的分组统计_Python 分组处理
  11. Three.js fbx文件导入
  12. 【技术邻】基于有限元方法的整车风噪仿真分析
  13. 查看或修改mysql数据库及表编码格式
  14. Calendar类、System类、StringBuilder类、包装类
  15. 在C#中实现SQLite的事务处理
  16. python爬虫——爬取马蜂窝景点翻页文字评论
  17. 报错“在要求输入数字处找到非数字字符”
  18. 友豆火山CPG插件开发002-环境配置和第一个例子
  19. 怎么通过财报选股票,一文教你学会选股!
  20. 深夜失眠中..谨以此纪念我两年的AC…

热门文章

  1. 【sklearn学习】决策树、分类树、剪枝策略
  2. extjs 表格数据重新加载_一个简单的更改让PyTorch读取表格数据的速度提高20倍:可大大加快深度学习训练的速度...
  3. java将图片变成圆角_android图片处理之让图片变成圆形
  4. python 逗号作用 语句间_Python 逗号的几种作用
  5. 8051中断系统介绍
  6. 【Opencv-Tools(一)】OpenCV中使用多线程处理图像
  7. Windows7上安装TensorFlow——基于Docker镜像
  8. TensorFlow(七)tf.nn库
  9. u-net语义分割_使用U-Net的语义分割
  10. 外联接、自联接与联合