当前位置: 首页 > article >正文

SpringBoot-MVC配置类与 Controller 的扫描

文章目录

  • 前言
  • 一、自动配置类位置
  • 二、自动配置类解析
    • 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,也就是 AbstractHandlerMethodMapping
	super.afterPropertiesSet();
}

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

3.2 RequestMappingHandlerMapping#initHandlerMethods

protected void initHandlerMethods() {
	// 遍历所有的 bean
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			// 处理符合条件的 bean
			processCandidateBean(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);
		// 获取 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提供了大量能使我们快速便捷地处理数据的函数和方法。


http://www.kler.cn/a/591721.html

相关文章:

  • 【Java】链表(LinkedList)(图文版)
  • QT学习笔记1
  • c语言笔记 存储期
  • 【实习经历Two:参与开源项目,学习并应用Git】
  • 解决qt中自定插件加载失败,不显示问题。
  • 报数游戏/补种未成活胡杨[E卷-hw_od]
  • HTML 新手入门:从零基础到搭建第一个静态页面(二)
  • 将温度预测的神经网络部署到服务器端,封装成api接口步骤
  • 高级java每日一道面试题-2025年3月04日-微服务篇[Eureka篇]-Eureka是什么?
  • Blender-MCP服务源码2-依赖分析
  • 再学:函数可见性、特殊函数、修饰符
  • ArcGIS Pro 制作风台路径图:从数据到可视化
  • MySQL5.7主从复制教程
  • 【HTML】三、表单与布局标签
  • 群体智能优化算法- 豪猪优化算法 (Crested Porcupine Optimization, CPO,含Matlab源代码)
  • 深入学习恩智浦 GoPoint:探索 AI Demo 与嵌入式 AI 开发
  • IPD解读——IPD重构产品研发与产品管理
  • 25届二本:春招希望不大,要做两手准备了
  • 【多线程】线程不安全问题
  • Couchbase Analytics 的结构