Spring Boot 中的 @EnableWebMvc
@EnableWebMvc
注解并不是像一般理解的那样在 Spring Boot 中使用 Spring MVC 必需要有的配置,而且并不是像字面意思那样启用 Spring MVC 的
功能。
@EnableWebMvc
的作用是引入 DelegatingWebMvcConfiguration
类来支持通过 WebMvcConfigurer
来对 WebMvc 进行配置。但其引入 DelegatingWebMvcConfiguration
的结果是导致 Spring MVC 相关的自动配置功能失效。
DelegatingWebMvcConfiguration 类是什么?
在理解 DelegatingWebMvcConfiguration
之前,我们要先看看它的父类 WebMvcConfigurationSupport
。
1 | This is the main class providing the configuration behind the MVC Java config. |
这个类的作用主要用于支持通过 Java 代码来配置 MVC,该类创建了诸如 RequestMappingHandlerMapping
、ViewResolver
或 ContentNegotiationManager
等
原先在 XML 中配置的内容,并提供了模板方法给子类实现用于自定义配置这些类的功能。
DelegatingWebMvcConfiguration
类扩展了这个类并实现了这些模板方法,将配置的实现继续委托给了 WebMvcConfigurer
接口的实现类。
DelegatingWebMvcConfiguration
类的部分代码如下:
1 |
|
WebMvcConfigurerComposite
类也实现了 WebMvcConfigurer
接口,其内部的实现将 DelegatingWebMvcConfiguration
模板方法的调用
委托给多个 WebMvcConfigurer
对象处理。
为什么引入 @EnableWebMvc
会导致 Spring MVC 自动配置失效?
因为这是 @EnableWebMvc
注解的功能之一。Spring Boot 的自动配置是在 @SpringBootApplication
注解中的 @EnableAutoConfiguration
启用的,@EnableWebMvc
表示将完全手动配置 Spring MVC。
1 | That's the expected behaviour. Using @EnableWebMvc disables the auto-configuration of Spring MVC. |
我们来看看实现原理,为什么会导致失效。
@EnableAutoConfiguration
注解引入了 AutoConfigurationImportSelector
类。AutoConfigurationImportSelector
实现了 DeferredImportSelector
接口,并在 @Configuration
处理完后加载 WebMvcAutoConfiguration
类(定义在 spring.factories 文件中)。Spring MVC 的自动配置功能是由 WebMvcAutoConfiguration
实现的,
该类的实现如下:
1 |
|
由以上代码 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
可以知道,WebMvcAutoConfiguration
配置类只有在不存在 WebMvcConfigurationSupport
的 Bean 时才启用。
上文说的 @EnableWebMvc
会引入 DelegatingWebMvcConfiguration
对象,而 DelegatingWebMvcConfiguration
类是 WebMvcConfigurationSupport
类的子类,所以 Spring MVC 的自动配置会失效。
建议
Spring MVC 自动配置失效后 application.properties 里一些 spring.* 开头配置就不会生效,不能方便的使用自动配置好的约定配置,同时很多开源组件
都依赖了这些配置,建议使用 Spring Boot 时尽量使用自动配置,只跟据需要作不同的配置。
实际上 WebMvcAutoConfiguration
的内部类 EnableWebMvcConfiguration
实现了和 @EnableWebMvc
一样的功能,自动配置开启的情况下依然
可以使用 WebMvcConfigurer
来进行自定义配置。
Spring Boot 中的 @EnableWebMvc