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