在springmvc中,如何根据url找到controller以及对应方法,依赖的是HandlerMapping接口的getHandler方法

在spring容器中默认注册的HandlerMapping有以下五种:

  • RequestMappingHandlerMapping
  • BeanNameUrlHandlerMapping
  • SimpleUrlHandlerMapping
  • RouterFunctionMapping
  • WelcomePageHandlerMapping

本文主要探索spring和springboot启动过程中RequestMappingHandlerMapping的注入

Spring中RequestMappingHandlerMapping的注入

环境

springmvc版本:5.1.9.RELEASE

过程

  1. 在springmvc中,使用注解需要在xml了加入注解声明

    <!-- 注解扫描 -->
    <context:component-scan base-package="com.xiaofan"/>
    <!--使用mvc注解声明 -->
    <mvc:annotation-driven/>
  2. 启动web服务器,我用的是tomcat8

  3. spring启动,注册BeanDefinition,

    spring会扫描xml文件,将配置文件中的bean信息注册成BeanDefinition,当发现springmvc的xml配置文件中有annotation-driven标签时,会调用AnnotationDrivenBeanDefinitionParser来解析该标签

    @Override
    @Nullable
    public BeanDefinition parse(Element element, ParserContext context) {
    ...
    // 前面省略代码
    RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
    handlerMappingDef.setSource(source);
    handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    handlerMappingDef.getPropertyValues().add("order", 0);
    handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); if (element.hasAttribute("enable-matrix-variables")) {
    Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
    handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
    } configurePathMatchingProperties(handlerMappingDef, element, context);
    // String HANDLER_MAPPING_BEAN_NAME = RequestMappingHandlerMapping.class.getName()
    readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
    // 后面省略代码
    ...
    return null;
    }
  4. spring将BeanDefinition通过反射实例化成bean注入到容器中

那么问题来了,如果没有mvc:annotation-driven标签,RequestMappingHandlerMapping还会被注入到spring容器中吗?

答:会的,前提是xml中没有配置任何一个HandlerMapping。

过程如下:

  1. 在启动过程中,会调用DispatcherServlet的init()方法(我也不知道是在哪个步骤调用的,希望知道的大佬告知,不胜感激)

  2. DispatcherServlet#onRefresh → DispatcherServlet#initStrategies → DispatcherServlet#initHandlerMappings

    private void initHandlerMappings(ApplicationContext context) {
    ...
    // 前面省略代码
    // 当没有配置任何handlerMapping时,则使用默认的handlerMapping
    if (this.handlerMappings == null) {
    // 从DispatcherServlet.properties拿org.springframework.web.servlet.HandlerMapping
    // 所以默认的有BeanNameUrlHandlerMapping和RequestMappingHandlerMapping
    // 最终还是调用BeanFactory#createBean()生成实例
    this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    if (logger.isTraceEnabled()) {
    logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
    "': using default strategies from DispatcherServlet.properties");
    }
    }
    }

SpringBoot中RequestMappingHandlerMapping的注入

在springboot中的注入,依赖的是springboot的自动装配

环境

Springboot版本:2.4.3

过程

  1. spring-boot-autoconfigure包下的spring.factories中有WebMvcAutoConfiguration

  2. WebMvcAutoConfiguration的内部类EnableWebMvcConfiguration#requestMappingHandlerMapping()

    @Bean
    @Primary
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
    @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
    // Must be @Primary for MvcUriComponentsBuilder to work
    return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
    resourceUrlProvider);
    }

问题

在spring环境中,DispatcherServlet的init方法在web服务器启动过程中就被调用了,而在springboot环境中,只有在DispatcherServlet被第一次调用的时候,才会执行init方法,有同学知道原因吗?不胜感激

最新文章

  1. 2.3 CMMI2级——项目跟踪和控制(Project Monitoring and Control)
  2. OpenSSL - 文件和字符MD5加密实现
  3. 阅读Nosql代码有感
  4. VMWare提供了三种工作模式上网
  5. MyBatis日期有坑
  6. linux 声音大小调整的命令
  7. KMP算法———模板
  8. CALayer CABasicAnimation
  9. ASP.NET - 一般处理程序获取session值
  10. InnoDB的约束机制
  11. 算法(Python)
  12. mac系统 pip3 install scrapy 失败 No local packages or working download links found for incremental&gt;=16.10.1
  13. ue4 蓝图方法备份
  14. NOIP2018退役记
  15. 【SVM、决策树、adaboost、LR对比】
  16. vue-cli 3.0 开启 Gzip 方法
  17. MYSQL中只知表名查询属于哪个SCHEMA
  18. java如何从一段html代码中获取图片的src路径
  19. 统计一个文件中出现字符&#39;a&#39;的次数
  20. oracl查询锁表语句

热门文章

  1. ShardingSphere 集成 CosId 实战
  2. CSAPP 之 DataLab 详解
  3. 嵌入:CAN
  4. Git分离头指针
  5. .NET程序设计实验2
  6. 【FineBI】FineBI连接阿里云mysql教程
  7. ABP框架之——数据访问基础架构
  8. GitHub 简介
  9. 阶段性总结 GDOI 2022 PJ
  10. 内网 Ubuntu 20.04 搭建 docusaurus 项目(或前端项目)的环境(mobaxterm、tigervnc、nfs、node)