SpringBoot-MVC配置类与 Controller 的扫描

news/2025/3/19 18:25:57/

文章目录

  • 前言
  • 一、自动配置类位置
  • 二、自动配置类解析
    • 2.1 WebMvcAutoConfiguration
      • 2.1.1 EnableWebMvcConfiguration
    • 2.2 DispatcherServletAutoConfiguration
  • 三、RequestMapping 的扫描过程
    • 3.1 RequestMappingHandlerMapping#afterPropertiesSet
    • 3.2 RequestMappingHandlerMapping#initHandlerMethods
    • 3.3 RequestMappingHandlerMapping#processCandidateBean
    • 3.4 RequestMappingHandlerMapping#detectHandlerMethods
  • 总结


前言

本章主要研究 SpringBoot 对于 MVC 的自动配置,本篇文章基于 springboot2.7.3

一、自动配置类位置

springboot 2.7 版本将推荐使用 org.springframework.boot.autoconfigure.AutoConfiguration.imports 这种配置,并且在 3 版本后废弃 spring.factories

在这里插入图片描述

二、自动配置类解析

2.1 WebMvcAutoConfiguration

当前类负责注入大量的 Bean 对象,并且还有好多个内部类,其中 EnableWebMvcConfiguration 是非常重要的一个配置类

2.1.1 EnableWebMvcConfiguration

此类继承了 DelegatingWebMvcConfiguration, 而 DelegatingWebMvcConfiguration 又继承了 WebMvcConfigurationSupport, 在 WebMvcConfigurationSupport 中注入了一个 RequestMappingHandlerMapping
RequestMappingHandlerMapping 实现了 InitializingBean 接口,所以在该类初始化的时候会调用 afterPropertiesSet(), 在该类中,该方法会扫描所有的 Controller 并解析所有的请求路径
在这里插入图片描述

2.2 DispatcherServletAutoConfiguration

这个自动配置类注入了 springmvc 的入口类 DispatcherServlet

三、RequestMapping 的扫描过程

从 2.1.1 可知 RequestMappingHandlerMapping 实现了InitializingBean 接口,那该类在 spring 的生命周期过程中会执行 afterPropertiesSet 方法

3.1 RequestMappingHandlerMapping#afterPropertiesSet

// RequestMappingHandlerMapping#afterPropertiesSet
@Override
@SuppressWarnings("deprecation")
public void afterPropertiesSet() {... // 调用父类的 afterPropertiesSet,也就是 AbstractHandlerMethodMappingsuper.afterPropertiesSet();
}// AbstractHandlerMethodMapping#afterPropertiesSet
@Override
public void afterPropertiesSet() {initHandlerMethods();
}

3.2 RequestMappingHandlerMapping#initHandlerMethods

protected void initHandlerMethods() {// 遍历所有的 beanfor (String beanName : getCandidateBeanNames()) {if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {// 处理符合条件的 beanprocessCandidateBean(beanName);}}handlerMethodsInitialized(getHandlerMethods());
}

3.3 RequestMappingHandlerMapping#processCandidateBean

protected void processCandidateBean(String beanName) {Class<?> beanType = null;try {// 获取 bean 类型beanType = obtainApplicationContext().getType(beanName);}catch (Throwable ex) {// An unresolvable bean type, probably from a lazy bean - let's ignore it.if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex);}}// 判断是不是 handler, 如果是获取里面的方法if (beanType != null && isHandler(beanType)) {detectHandlerMethods(beanName);}
}// RequestMappingHandlerMapping#isHandler
// 判断该类上是否标注了 @Controller 或者 @RequestMapping
@Override
protected boolean isHandler(Class<?> beanType) {return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

3.4 RequestMappingHandlerMapping#detectHandlerMethods

protected void detectHandlerMethods(Object handler) {Class<?> handlerType = (handler instanceof String ?obtainApplicationContext().getType((String) handler) : handler.getClass());if (handlerType != null) {Class<?> userType = ClassUtils.getUserClass(handlerType);// 获取 HandlerMappingMap<Method, T> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> {try {// 这个地方返回的是 RequestMappingInforeturn getMappingForMethod(method, userType);}catch (Throwable ex) {throw new IllegalStateException("Invalid mapping on handler class [" +userType.getName() + "]: " + method, ex);}});...// 注册 HandlerMethod// 里面的代码都很简单了methods.forEach((method, mapping) -> {Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);registerHandlerMethod(handler, invocableMethod, mapping);});}
}


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。


http://www.ppmy.cn/news/1580385.html

相关文章

【Java】Devops、CI/CD、jenkins

https://heuqqdmbyk.feishu.cn/docx/ITjadnZfAoxauXxqgiccu9b6nGg https://www.bilibili.com/video/BV1j8411N7Bm?spm_id_from333.788.videopod.episodes&vd_source6bec1f5b9fe3a91a9829e3a951692cc5&p169 CI/CD 是近年来企业有效实施DevOps的具体方案。 CI/CD 包含了…

Prometheus 和 Grafana科普介绍

1. Prometheus 简介 1.1 什么是 Prometheus&#xff1f; Prometheus 是一个开源的 时间序列数据库 和 监控系统&#xff0c;最初由 SoundCloud 开发&#xff0c;现在是 CNCF&#xff08;云原生计算基金会&#xff09; 的毕业项目。它专注于实时监控和告警&#xff0c;特别适合…

STM32项目分享:STM32智能窗户

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; STM32智能窗户 &#xff08;资料分享见文末&…

Excel VBA实现智能合并重复元器件数据(型号去重+数量累加)

Excel VBA实现智能合并重复元器件数据&#xff08;型号去重数量累加&#xff09; 关键词&#xff1a;Excel自动化、VBA数据处理、重复项合并、元器件管理 功能概述 本工具针对电子元器件库存表/采购清单等场景&#xff0c;实现&#xff1a; 按型号列自动识别重复元器件智能合…

Linux的root用户 、用户组

su和exit命令 1、su命令 就是用于账户切换的系统命令&#xff0c;其来源英文单词:Switch User 语法: su [-] [用户名] - 符号是可选的,表示是否在切换用户后加载环境变量&#xff0c;建议带上 参数: 用户名&#xff0c;表示要切换的用户,用户名也可以省略,省略表示切换到…

Ubuntu 安装 gdb 错误解决方案

Ubuntu 安装 gdb 错误解决方案 一、APT 锁定问题 错误内容 Waiting for cache lock: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 922问题分析 在 Ubuntu 系统中执行 apt install 时&#xff0c;若出现上述错误&#xff0c;说明进程 922 正在占…

Spring Boot启动流程及源码实现深度解析

Spring Boot启动流程及源码实现深度解析 一、启动流程概述 Spring Boot的启动流程围绕SpringApplication类展开&#xff0c;核心流程可分为以下几个阶段&#xff1a; 初始化阶段&#xff1a;推断应用类型&#xff0c;加载ApplicationContextInitializer和ApplicationListene…

C++模版(进阶)

文章目录 一、非类型模版参数二、模版的特化2.1 概念2.2 函数模版特化2.2.1 函数模版特化为指针类型注意事项 2.3 类模版特化2.3.1 全特化2.3.2 偏特化(半特化)2.3.3 类模板特化应用示例 三、模版分离编译3.1 什么是分离编译&#xff1f;3.2 模版的分离编译3.3 解决方法! 四、模…