SpringBoot-MVC配置类与 Controller 的扫描

文章目录


前言

本章主要研究 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

java 复制代码
// RequestMappingHandlerMapping#afterPropertiesSet
@Override
@SuppressWarnings("deprecation")
public void afterPropertiesSet() {
	... 
	// 调用父类的 afterPropertiesSet,也就是 AbstractHandlerMethodMapping
	super.afterPropertiesSet();
}

// AbstractHandlerMethodMapping#afterPropertiesSet
@Override
public void afterPropertiesSet() {
	initHandlerMethods();
}

3.2 RequestMappingHandlerMapping#initHandlerMethods

java 复制代码
protected void initHandlerMethods() {
	// 遍历所有的 bean
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			// 处理符合条件的 bean
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

3.3 RequestMappingHandlerMapping#processCandidateBean

java 复制代码
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

java 复制代码
protected void detectHandlerMethods(Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class<?> userType = ClassUtils.getUserClass(handlerType);
		// 获取 HandlerMapping
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
						// 这个地方返回的是 RequestMappingInfo
						return 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提供了大量能使我们快速便捷地处理数据的函数和方法。

相关推荐
用户214118326360228 分钟前
Claude Skills 新玩法:用 skill-creator 10 分钟搞定 Excel 报表自动化,职场人必学
后端
東雪木1 小时前
Spring Boot 2.x 集成 Knife4j (OpenAPI 3) 完整操作指南
java·spring boot·后端·swagger·knife4j·java异常处理
天使街23号1 小时前
go-dongle v1.2.0 发布,新增 SM2 非对称椭圆曲线加密算法支持
开发语言·后端·golang
陈果然DeepVersion1 小时前
Java大厂面试真题:从Spring Boot到AI微服务的三轮技术拷问(二)
spring boot·redis·spring cloud·微服务·ai·java面试·rag
用户69371750013842 小时前
Kotlin 协程基础入门系列:从概念到实战
android·后端·kotlin
Q_Q19632884752 小时前
python+django/flask的医院财务管理系统
spring boot·python·django·flask·node.js
半旧夜夏2 小时前
【Gateway】服务调用和网关配置攻略
java·spring boot·spring cloud·gateway
Moonbit2 小时前
MoonBit Pearls Vol.14:哈希表避坑指南
后端·算法·编程语言
Moonbit3 小时前
MoonBit Pearls Vol.13: 使用 MoonBit 开发一个 HTTP 文件服务器
服务器·后端·http
一 乐3 小时前
个人博客|博客app|基于Springboot+微信小程序的个人博客app系统设计与实现(源码+数据库+文档)
java·前端·数据库·spring boot·后端·小程序·论文