1. 下图是springmvc的执行流程

    图片来源:https://www.jianshu.com/p/8a20c547e245


     DispatcherServlet根据url定位到Controller和方法,依赖的是HandlerMapping接口的各个实现类,其中,RequestMappingHandlerMapping是专门用来处理注解方式的Controller的

    下面,我们分RequestMappingHandlerMapping的加载以及RequestMappingHandlerMapping如何根据url定位Controller两部分来讲

    RequestMappingHandlerMapping加载过程

    1. RMHP在系统启动时会被注册成bean,见《springmvc源码笔记-HandlerMapping注入》

    2. 因为RMHP实现了InitializingBean接口,在bean加载完成后会自动调用afterPropertiesSet方法,在此方法中调用了AbstractHandlerMethodMapping#initHandlerMethods()来实现初始化

      protected void initHandlerMethods() {
      // 遍历所有的bean
      for (String beanName : getCandidateBeanNames()) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
      processCandidateBean(beanName);
      }
      }
      handlerMethodsInitialized(getHandlerMethods());
      } protected void processCandidateBean(String beanName) {
      Class<?> beanType = null;
      try {
      beanType = obtainApplicationContext().getType(beanName);
      }
      ......
      // isHandler判断类是否有Controller或者RequestMapping注解
      if (beanType != null && isHandler(beanType)) {
      detectHandlerMethods(beanName);
      }
      } protected void detectHandlerMethods(Object handler) {
      ......
      if (handlerType != null) {
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      // 遍历类的所有方法
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
      (MethodIntrospector.MetadataLookup<T>) method -> {
      try {
      // 获取方法上的映射(会读取方法上的RequestMapping注解获取url)
      return getMappingForMethod(method, userType);
      }
      catch (Throwable ex) {
      throw new IllegalStateException("Invalid mapping on handler class [" +
      userType.getName() + "]: " + method, ex);
      }
      });
      ......
      methods.forEach((method, mapping) -> {
      Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
      // 将映射关系放入AbstractHandlerMethodMapping.mappingRegistry中
      registerHandlerMethod(handler, invocableMethod, mapping);
      });
      }
      }

    RequestMappingHandlerMapping解析过程

    1. DispatcherServlet继承HttpServlet,所以执行链是FrameworkServlet#doGet→DispatcherServlet#doService→DispatcherServlet#doDispatch→DispatcherServlet#getHandler

      protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      if (this.handlerMappings != null) {
      // handlerMappings已在onRefresh方法中初始化
      for (HandlerMapping mapping : this.handlerMappings) {
      // 第一个mapping就是RequestMappingHandlerMapping
      // 获取处理程序,也就是url对应的controller和method
      HandlerExecutionChain handler = mapping.getHandler(request);
      if (handler != null) {
      return handler;
      }
      }
      }
      return null;
      } // AbstractHandlerMapping#getHandler->RequestMappingHandlerMapping#getHandlerInternal->AbstractHandlerMapping#lookupHandlerMethod
      protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
      // lookupPath就是请求路径
      List<Match> matches = new ArrayList<>();
      // 获取url路径匹配项
      List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
      if (directPathMatches != null) {
      // 添加映射匹配集合
      addMatchingMappings(directPathMatches, matches, request);
      }
      if (matches.isEmpty()) {
      addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
      }
      if (!matches.isEmpty()) {
      ......
      // 至此,根据url获取到controller和method
      return bestMatch.getHandlerMethod();
      } else {
      return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
      }
      } private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
      for (T mapping : mappings) {
      T match = getMatchingMapping(mapping, request);
      if (match != null) {
      // this.mappingRegistry.getRegistrations().get(mapping)就是获取HandlerMethodMapping
      // HandlerMethodMapping保存controller和method信息的类
      matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));
      }
      }
      }

springmvc源码笔记-RequestMappingHandlerMapping的更多相关文章

  1. springmvc源码笔记-HandlerMapping注入

    在springmvc中,如何根据url找到controller以及对应方法,依赖的是HandlerMapping接口的getHandler方法 在spring容器中默认注册的HandlerMappin ...

  2. springMVC源码笔记

    springMVC 设计总览 下图来源:https://www.cnblogs.com/fangjian0423/p/springMVC-directory-summary.html 下图来源:htt ...

  3. springmvc源码笔记-HandlerMethodReturnValueHandler

    返回值解析器 用于对controller的返回值进行二次处理 结构 // 返回值解析器 public interface HandlerMethodReturnValueHandler { // 判断 ...

  4. SpringMVC源码情操陶冶-AnnotationDrivenBeanDefinitionParser注解解析器

    mvc:annotation-driven节点的解析器,是springmvc的核心解析器 官方注释 Open Declaration org.springframework.web.servlet.c ...

  5. SpringMVC源码情操陶冶-DispatcherServlet简析(二)

    承接前文SpringMVC源码情操陶冶-DispatcherServlet类简析(一),主要讲述初始化的操作,本文将简单介绍springmvc如何处理请求 DispatcherServlet#doDi ...

  6. SpringMVC源码情操陶冶-AbstractHandlerMethodMapping

    承接前文SpringMVC源码情操陶冶-AbstractHandlerMapping,本文将介绍如何注册HandlerMethod对象作为handler 类结构瞧一瞧 public abstract ...

  7. SpringMVC源码情操陶冶-RequestMappingHandlerAdapter适配器

    承接前文SpringMVC源码情操陶冶-HandlerAdapter适配器简析.RequestMappingHandlerAdapter适配器组件是专门处理RequestMappingHandlerM ...

  8. springMVC源码分析--AbstractHandlerMethodMapping注册url和HandlerMethod对应关系(十一)

    在上一篇博客springMVC源码分析--AbstractHandlerMethodMapping获取url和HandlerMethod对应关系(十)中我们简单地介绍了获取url和HandlerMet ...

  9. SpringMVC源码阅读:拦截器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

随机推荐

  1. 【面试普通人VS高手系列】为什么要使用Spring 框架?

    一个工作了4年的小伙伴,他说他从线下培训就开始接触Spring,到现在已经快5年时间了. 从来没有想过,为什么要使用Spring 框架. 结果在面试的时候,竟然遇到一个这样的问题. 大脑一时间短路了, ...

  2. 用上这个 Mock 神器,让你的开发爽上天!

    ​ 前端的痛苦 作为前端,最痛苦的是什么时候? 每个迭代,需求文档跟设计稿都出来了,静态页面唰唰两天就做完了.可是做前端又不是简单地把后端吐出来的数据放到页 面上就完了,还有各种前端处理逻辑啊. 后端 ...

  3. go 语言开发1 环境配置和语言基础

    Go 语言环境配置 windows 环境变量: 设置 GOROOT (安装路径),GOPATH(工程目录) Path 中加入 %GOROOT%/bin 和 %GOPATH%/bin mac 环境变量: ...

  4. ifconfig出现bash: ifconfig:command not found解决办法之解决连环问题

    Centos7中没有安装ifconfig命令的解决方法 在这之前,centos7最小化安装默认是不能联网的,首先必须切换到root用户,再解决网络问题 一.      切换到root用户 二.     ...

  5. HCNP Routing&Switching之MSTP

    前文我们了解了RSTP保护相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16255918.html:今天我们来了解下MSTP相关话题: MSTP技术背 ...

  6. 520表白小程序设计Python代码详解(PyQt5界面,B站动漫风)

    摘要:介绍一个动漫风的表白小程序,界面使用Python以及PyQt实现,界面样式经过多次美化调整,使得整体清新美观.本文详细介绍代码设计和实现过程,不仅是居家表白必备,而且适合新入门的朋友学习界面设计 ...

  7. vue新手入门之使用vue框架搭建用户登录注册案例,手动搭建webpack+Vue项目(附源码,图文详解,亲测有效)

    前言 本篇随笔主要写了手动搭建一个webpack+Vue项目,掌握相关loader的安装与使用,包括css-loader.style-loader.vue-loader.url-loader.sass ...

  8. Unity实现”对象池管理器“

    前言:警告!这可能是坨屎,空闲时间写成,仅作娱乐 在Unity中生成或销毁一个物体会占用较大的资源,如果是制作FPS射击游戏,子弹生成更是雪上加霜.所以我自己写了一个PoolManager,不能和网上 ...

  9. 在 .NET 中使用 FixedTimeEquals 应对计时攻击

    计时攻击 在计算机安全中,计时攻击(Timing attack)是旁道攻击 (Side-channel attack) 的一种,而旁道攻击是根据计算机处理过程发出的信息进行分析,包括耗时,声音,功耗等 ...

  10. 计算机网络 - OSI 7层网络模型各层对应的功能

    应用层 - 负责给应用程序提供统一的接口 表示层 - 负责把数据的解压缩和编码 会话层 - 负责会话的管理(建立和终止) 传输层 - 负责端到端的数据传输 网络层 - 负责数据的路由.转发.分片 数据 ...