@EnableWebMvc如何禁止@EnableAutoConfiguration

今天一直纠结于一个问题,问题的来源是解析@EnableWebMvc 、WebMvcConfigurationSupport和WebMvcConfigurationAdapter

博客中总结出来的三点使用@EnableWebMvc的规则:

  1. @EnableWebMvc+extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
  2. extends WebMvcConfigurationSupport,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
  3. extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式依旧使用springboot的@EnableAutoConfiguration中的设置

我看完就在想到底是什么导致的三个规则,查spring boot的文档,也有相关表述

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

以及 这里

As in normal MVC usage, any WebMvcConfigurer beans that you provide can also contribute converters by overriding the configureMessageConverters method. However, unlike with normal MVC, you can supply only additional converters that you need (because Spring Boot uses the same mechanism to contribute its defaults). Finally, if you opt out of the Spring Boot default MVC configuration by providing your own @EnableWebMvc configuration, you can take control completely and do everything manually by using getMessageConverters from WebMvcConfigurationSupport.

也就是说上面博客里不是瞎说啊,那内部的原因呢?我就很奇怪。找了一下午,终于理顺了,赶紧写下来,别忘了。

首先我们要搞清楚@EnableAutoConfiguration的设置到底代表的是啥,从自动装配的原理入手,我们翻spring.factories,和mvc有关的自动装配类,是如下几个:

org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\

凭感觉,其中WebMvcAutoConfiguration一定和Spring MVC在Spring boot中自动装配最有关,找下去,这是class的声明。

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

可以看到,当WebMvcConfigurationSupport类不存在的时候,该自动装配类才会创建出来,也就是说,如果我们使用@EnableWebMvc,@EnableWebMvc就相当于导入了WebMvcConfigurationSupport类,这个时候,spring boot的自动装配就不会发生了,这个时候,我们能用的,只有WebMvcConfigurationSupport提供的若干个配置

至此,可以说明三条规则的前两条,无论是使用@EnableWebMvc还是扩展WebMvcConfigurationSupport类,spring都会创建一个WebMvcConfigurationSupport的类,进而屏蔽掉自动装配类WebMvcAutoConfiguration

那么第三条规则呢?为何扩展WebMvcConfigurationAdapter(Java8 有接口默认方法后,该类被废弃,转为使用WebMvcConfigurer接口,下文我们统一用WebMvcConfigurer)不会屏蔽掉spring boot的自动装配呢?

这要再说WebMvcConfigurer的工作方式了,实际上,使用@EnableWebMvc引入的类不是WebMvcConfigurationSupport,而是DelegatingWebMvcConfiguration
DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport,并且DelegatingWebMvcConfiguration通过依赖注入,持有Spring 容器所有WebMvcConfigurer实现类的一个List,所有对spring mvc的自定义的WebMvcConfigurer,都会挂到DelegatingWebMvcConfiguration上去。

WebMvcAutoConfiguration内部,创建了一个继承了DelegatingWebMvcConfiguration的内部类EnableWebMvcConfiguration,这个类,一方面,提供了缺失的WebMvcConfigurationSupport的功能,另一方面,就起到了收集所有WebMvcConfigurer,调用它们的方法的作用。

这样,上述引用的第三条规则也就理出来了。

最后我们做一个总结:
1. 无论是使用@EnableWebMvc还是WebMvcConfigurationSupport,都会禁止Spring boot的自动装配,只有使用WebMvcConfigurer才不会
2. 虽然禁止了Spring boot的自动装配,但是WebMvcConfigurationSupport本身,还是会注册一系列的MVC相关的bean的,从附加的api可以看到
3. WebMvcAutoConfiguration自动装备,其实会创建一个WebMvcConfigurationSupport的子类,叫EnableWebMvcConfiguration

到此,其实还有一个延伸问题:SPring boot相比于@EnableWebMvc,多提供了哪些Bean?
待我研究一下,再说吧。

猜你喜欢

转载自blog.csdn.net/lqadam/article/details/80637335