全网最深分析:SpringBoot MVC自动配置失效的原因

推荐学习

  • 肝了十天半月 , 献上纯手绘“Spring/Cloud/Boot/MVC”全家桶脑图
  • 金三银四第一天 , 啃透这些SpringBoot知识点 , 还怕干不赢面试官?

全网最深分析:SpringBoot MVC自动配置失效的原因文章插图
前言在看完SpringBoot核心原理后 , 突然想到之前开发中遇到的MVC自动失效的问题 , 虽然网上有很多文章以及官方文档都说明了原因 , 但还是想亲自看一看 , 本以为很简单的事情 , 没想到却引发出一个较复杂的问题 , 请教了很多人都没有得到结果 , 网上文章也没有写清楚的 , 最后还是自己搞了很久才弄明白的 , 此篇主要记录自己的一个分析过程 ,。
正文引出问题
全网最深分析:SpringBoot MVC自动配置失效的原因文章插图
上面是SpringBoot MVC的自动配置 , 问题是这样的 , 当我们需要自己配置MVC时 , 有三种选择:
  • 实现WebMvcConfigurer接口
  • 继承WebMvcConfigurerAdapter类
  • 继承WebMvcConfigurationSupport类
在老版本中我们常用的做法就是继承WebMvcConfigurerAdapter类 , 这个类本身是实现了WebMvcConfigurer接口的 , 因为老版本JDK接口没有默认方法 , 直接实现WebMvcConfigurer比较繁琐 , 而后来接口可以有默认方法了 , WebMvcConfigurerAdapter就被标记为过时了 , 所以我们现在配置MVC只需要实现WebMvcConfigurer接口或者继承WebMvcConfigurationSupport , 但是后者会导致SpringBoot的配置失效 , 因为在自动配置类上有@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)这样一个注解 , 表示没有WebMvcConfigurationSupport类及其子类的实例时才会加载自动配置(另外使用@EnableWebMvc注解也会导致自动配置失效) 。
MVC自动配置失效的原因就是这个了 , 基本上所有网上的文章分析到这一步也就完了 , 但是注意上图我画的红方框 , 在这个自动配置类中有两个静态内部类 , 我们知道静态内部类是优于外部类加载的(SpringBoot自动配置大量使用了此特性) , 而其中EnableWebMvcConfiguration这个类 , 我注意到它是继承自DelegatingWebMvcConfiguration , 而DelegatingWebMvcConfiguration又继承自WebMvcConfigurationSupport类 , 相信看到这你也应该会有疑惑了 , 为什么这个配置类没有导致自动配置失效 , 而我们自己实现的就会?
分析过程【全网最深分析:SpringBoot MVC自动配置失效的原因】我知道配置类的解析注册是在ConfigurationClassPostProcessor类中 , 而这个类我前面的文章多次分析过 , 虽然这个类的实现流程不难 , 但细节非常绕 , 所以之前没有深挖 。 遇到这个问题时 , 我首先想的是对这个类的理解不够深刻 , 因此第一时间想到仔细研究这个类 , 在花费了大量时间断点分析后 , 却没有太大的收获 。接着我又想 , 是不是配置类的注册顺序在自动配置的后面 。 这里我就犯了一个显而易见的错误 , 因为我考虑的是注册的顺序 , 不是实例化 。 因为ConditionalOnMissingBean注解是没有指定bean的实例时才会去加载 , 而我脑海里当时想成了ConditionalOnMissingClass 。 所以我在DefaultListableBeanFactory中的registerBeanDefinition和preInstantiateSingletons方法上打上了断点 , 力图确认注册顺序如我所想:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);if (existingDefinition != null) {....this.beanDefinitionMap.put(beanName, beanDefinition);}else {if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);List updatedDefinitions = new ArrayList


推荐阅读