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. 一个Python中优雅的数据分块方法

    背景 看到这个标题你可能想一个分块能有什么难度?还值得细说吗,最近确实遇到一个有意思的分块函数,写法比较巧妙优雅,所以写一个分享. 日前在做需求过程中有一个对大量数据分块处理的场景,具体来说就是几十万 ...

  2. [数学基础] 4 欧几里得算法&扩展欧几里得算法

    欧几里得算法 欧几里得算法基于的性质: 若\(d|a, a|b\),则\(d|(ax+by)\) \((a,b)=(b,a~mod~b)\) 第二条性质证明: \(\because a~mod~b=a ...

  3. 数据库、MySQL下载与安装、基本SQL语句

    数据演变史 # 1.单独的文本文件 没有固定的存放位置 没有固定的数据格式 '''程序彼此无法兼容 没有统一的标准''' # 2.软件开发目录规范 按照文件功能的不同规定了相应的位置 '''文件查找变 ...

  4. 简单的 useState 实现

    简单的 useState 实现 本文写于 2020 年 10 月 21 日 以下是一段非常简单的 React 代码: const App = () => { const [n, setN] = ...

  5. Git生成ssh keys加密算法ed25519

    1:桌面右击后出现Git push hehe点击进入直接输入以下命令 ①:ssh-keygen -t ed25519 -f my_github_ed25519 -C "xxxxx" ...

  6. UML类图六种关系的总结

    在UML类图中,常见的有以下几种关系: 泛化(Generalization):继承的关系,实线带三角形箭头,指向父类. 实现(Realization):实现的关系,虚线带三角形箭头,指向接口. 关联( ...

  7. K8S 使用Kubeadm搭建高可用Kubernetes(K8S)集群 - 证书有效期100年

    1.概述 Kubenetes集群的控制平面节点(即Master节点)由数据库服务(Etcd)+其他组件服务(Apiserver.Controller-manager.Scheduler...)组成. ...

  8. Python模块Ⅰ

    Python模块Ⅰ part1 模块的定义/取别名 自定义模块 什么是模块:模块的本质就是.py文件,封装语句的最小单位 模块中出现的变量,for循环,if结构,函数定义...称为模块成员 模块的运行 ...

  9. 浏览器上写代码,4核8G微软服务器免费用,Codespaces真香

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 一图胜千言 先上图,下面是欣宸在自己的iPad Pro ...

  10. 探究Presto SQL引擎(3)-代码生成

    ​ vivo 互联网服务器团队- Shuai Guangying 探究Presto SQL引擎 系列:第1篇<探究Presto SQL引擎(1)-巧用Antlr>介绍了Antlr的基本用法 ...