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. HMS Core地理围栏能力助你实现指定范围人群的精准消息推送

    精准推送是移动端产品留存阶段的主要运营手段,精准推送常常会与用户画像紧密结合,针对用户的喜好.画像,采用不同策略,但基于用户所属区域推送消息却很难实现.目前市面上大多数第三方消息推送服务商,在系统未深 ...

  2. Spring 源码(9)Spring Bean的创建过程的前期准备

    回顾总结 到目前为止,Spring源码中AbstractApplicationContext#refresh方法的已经解读到第11个方法finishBeanFactoryInitialization, ...

  3. pyhon对excel的xls与xlsx的读取,写入

    import shutilimport osfrom openpyxl import load_workbookfrom xlutils.copy import copyimport win32com ...

  4. 《Java编程思想》读书笔记(二)

    三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...

  5. 如何在 pyqt 中解决启用 DPI 缩放后 QIcon 模糊的问题

    问题描述 如今显示器的分辨率越来越高,如果不启用 DPI 缩放,软件的字体和图标在高分屏下就会显得非常小,看得很累人.从 5.6 版本开始,Qt 便能支持 DPI 缩放功能,Qt6 开始这个功能是默认 ...

  6. 关于『进击的Markdown』:第五弹

    关于『进击的Markdown』:第五弹 建议缩放90%食用 路漫漫其修远兮,吾将上下而求索.  我们要接受Mermaid的考验了呢  Markdown 语法真香(一如既往地安利) ( 进击吧!Mark ...

  7. 【摸鱼神器】UI库秒变LowCode工具——列表篇(二)维护json的小工具

    上一篇介绍了一下如何实现一个可以依赖 json 渲染的列表控件,既然需要 json 文件,那么要如何维护这个 json 文件就成了重点,如果没有好的维护方案的话,那么还不如直接用UI库. 所以需要我们 ...

  8. Hyperledger Fabric 智能合约开发及 fabric-sdk-go/fabric-gateway 使用示例

    前言 在上个实验 Hyperledger Fabric 多组织多排序节点部署在多个主机上 中,我们已经实现了多组织多排序节点部署在多个主机上,但到目前为止,我们所有的实验都只是研究了联盟链的网络配置方 ...

  9. 网络协议之:memcached binary protocol详解

    目录 简介 memcached的协议包 memcached命令举例 总结 简介 前面讲到了memcached的文本协议,虽然文本协议看起来非常简单,但是对于客户端来说一般还是会选择效率更高的二进制协议 ...

  10. python亲密数设计

    '''亲密数 (如果a的所有正因子和等于b,b的所有正因子和等于a,因子包括1但不包括本身,且a不等于b,则称a,b为亲密数对.一般通过叠代编程求出相应的亲密数对)'''n = 3000def fun ...