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

<>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;removeManualSingletonName(beanName);}}else {// Still in startup registration phasethis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;} } public void preInstantiateSingletons() throws BeansException {List beanNames = new ArrayList<>(this.beanDefinitionNames);.... }
全网最深分析:SpringBoot MVC自动配置失效的原因文章插图
但结果beanDefinitionNames中的顺序却是两个静态内部类在前 , 也就是说静态内部类肯定是在外部类之前就注册到IOC容器中了 , 这下我就傻了 。 但幸好也是因此 , 否则我就该认为这就是结果了 。 最终我想到了应该看类的实例化顺序 , 但是正常情况下类的实例化顺序就是上面的断点图中的顺序 , 我想会不会是有什么类依赖了WebMvcAutoConfiguration , 导致它提前实例化 。 于是我将断点又设置到AbstractBeanFactory中的doGetBean方法并加上了条件(不得不说idea的功能非常强大 , 回到上一个调用点、给断点设置条件、调用堆栈信息大大节省了我的调试时间):
全网最深分析:SpringBoot MVC自动配置失效的原因文章插图
然后启动项目就可以看到首先实例化的果然是WebMvcAutoConfiguration类 , 这样就搞清楚了为什么EnableWebMvcConfiguration没有导致自动配置失效 。但是还没完 , 为什么自动配置类会在静态内部类之前实例化呢?是由谁触发的呢?继续深入 , 这时我想到了看调用栈:
全网最深分析:SpringBoot MVC自动配置失效的原因文章插图
粗略看一下调用栈信息 , 如果对Spring源码熟悉 , 可以发现自动配置类的实例化是在instantiateUsingFactoryMethod中触发的:
String factoryBeanName = mbd.getFactoryBeanName();if (factoryBeanName != null) {if (factoryBeanName.equals(beanName)) {throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,"factory-bean reference points back to the same bean definition");}factoryBean = this.beanFactory.getBean(factoryBeanName);if (mbd.isSingleton()}factoryClass = factoryBean.getClass();isStatic = false;}else {// It's a static factory method on the bean class.if (!mbd.hasBeanClass()) {throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,"bean definition declares neither a bean class nor a factory-bean reference");}factoryBean = null;factoryClass = mbd.getBeanClass();isStatic = true;}这段代码在bean实例化的那一篇分析过 , 这个方法的作用是通过factoryMethod实例化当前的BeanDefinition , 而实例化该BD优先会实例化factoryBeanName属性指向的Bean , 这里的factoryBeanName就是org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration , factoryMethod则是formContentFilter , 而这两个属性的设置则是在ConfigurationClassPostProcessor解析@Configuration和@Bean就设置好了(@Bean标注的方法名会设置到factoryMethod , 而该方法所在配置类的名称就是factoryBeanName) , 这里就不展开分析了 。
@Configuration(proxyBeanMethods = false)@ConditionalOnWebApplication(type = Type.SERVLET)@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class })public class WebMvcAutoConfiguration { public static final String DEFAULT_PREFIX = ""; public static final String DEFAULT_SUFFIX = ""; private static final String[] SERVLET_LOCATIONS = { "/" }; @Bean @ConditionalOnMissingBean(HiddenHttpMethodFilter.class) @ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false) public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {return new OrderedHiddenHttpMethodFilter(); } @Bean @ConditionalOnMissingBean(FormContentFilter.class) @ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter", name = "enabled", matchIfMissing = true) public OrderedFormContentFilter formContentFilter() {return new OrderedFormContentFilter(); }......}


推荐阅读