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提供了大量能使我们快速便捷地处理数据的函数和方法。

相关推荐
想用offer打牌9 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX10 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了10 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
爬山算法11 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
猫头虎11 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
Moment11 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
Cobyte12 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc
程序员侠客行13 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
Honmaple13 小时前
QMD (Quarto Markdown) 搭建与使用指南
后端
MZ_ZXD00113 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php