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. 【多线程】线程强制执行 join()

    线程强制执行 join() Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞 : 可以想象成插队. 代码示例: /** * @Description 测试join方法 * @Auth ...

  2. form表单与css选择器

    目录 form表单 action属性 input标签 lable标签 select标签 textarea标签 补充 网络请求方式 CSS简介 CSS基本选择器 组合选择器 属性选择器 分组与嵌套 伪类 ...

  3. [python][flask] Flask 图片上传与下载例子(支持漂亮的拖拽上传)

    目录 1.效果预览 2.新增逻辑概览 3.tuchuang.py 逻辑介绍 3.1 图片上传 3.2 图片合法检查 3.3 图片下载 4.__init__.py 逻辑介绍 5.upload.html ...

  4. pip国内源配置

    Python 的一大优点就是丰富的类库,所以我们经常会用 pip 来安装各种库,所以对于Python开发用户来讲,PIP安装软件包是家常便饭.但国外的源下载速度实在太慢,浪费时间.而且经常出现下载后安 ...

  5. point pair feature在2D图像匹配中的应用

    point pair feature在2D图像匹配中的应用 point pair feature(ppf) @article{BertramDrost2010ModelGM, title={Model ...

  6. Java实现http大文件流读取并批量插入数据库

    1.概述 请求远程大文本,使用流的方式进行返回.需要设置http链接的超时时间 循环插入到List中,使用mybatis-plus批量插入到mysql中 2.需求 两台服务器 大文件放到其中一台服务器 ...

  7. 【抬杠C#】如何实现接口的base调用

    背景 在三年前发布的C#8.0中有一项重要的改进叫做接口默认实现,从此以后,接口中定义的方法可以包含方法体了,即默认实现.不过对于接口的默认实现,其实现类或者子接口在重写这个方法的时候不能对其进行ba ...

  8. python requires模块 https请求 由于TLS协议版本太高导致错误

    错误提示 requests.exceptions.SSLError: HTTPSConnectionPool(host='air.cnemc.cn', port=18007): Max retries ...

  9. 1.为什么要从古典概率入门概率学《zobol的考研概率论教程》

    在入门概率论与数理统计这门课中,刚开始我们都会从古典概率开始学习,为什么要选择它呢?这是因为古典概率作为一种将生活中的事情简化为有限种情况,并假设它们的发生可能差不多的手段,十分的好用且简洁. 这里我 ...

  10. 记安装AWVS14过程踩的坑

    由于之前的AWVS14用着用着无法扫描了,一扫就是失败,一气之下就重装系统了.重装系统后发现安装还是不行,折腾了好久,终于找到方法了. 安装acunetix_14.1.210324124.exe 没啥 ...