Spring Boot 中的 @EnableWebMvc

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,该类创建了诸如 RequestMappingHandlerMappingViewResolverContentNegotiationManager
原先在 XML 中配置的内容,并提供了模板方法给子类实现用于自定义配置这些类的功能。

DelegatingWebMvcConfiguration 类扩展了这个类并实现了这些模板方法,将配置的实现继续委托给了 WebMvcConfigurer
接口的实现类。

DelegatingWebMvcConfiguration 类的部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();


@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}


@Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
this.configurers.configurePathMatch(configurer);
}
// ...
}

WebMvcConfigurerComposite 类也实现了 WebMvcConfigurer 接口,其内部的实现将 DelegatingWebMvcConfiguration 模板方法的调用
委托给多个 WebMvcConfigurer 对象处理。

为什么引入 @EnableWebMvc 会导致 Spring MVC 自动配置失效?

因为这是 @EnableWebMvc 注解的功能之一。Spring Boot 的自动配置是在 @SpringBootApplication 注解中的 @EnableAutoConfiguration 启用的,
@EnableWebMvc 表示将完全手动配置 Spring MVC。

1
2
That's the expected behaviour. Using @EnableWebMvc disables the auto-configuration of Spring MVC.
---Andy Wilkinson

我们来看看实现原理,为什么会导致失效。

@EnableAutoConfiguration 注解引入了 AutoConfigurationImportSelector 类。AutoConfigurationImportSelector 实现了 DeferredImportSelector
接口,并在 @Configuration 处理完后加载 WebMvcAutoConfiguration 类(定义在 spring.factories 文件中)。Spring MVC 的自动配置功能是由 WebMvcAutoConfiguration 实现的,
该类的实现如下:

1
2
3
4
5
6
7
8
9
10
@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 {
// ...
}

由以上代码 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 可以知道,WebMvcAutoConfiguration 配置类只有在不存在 WebMvcConfigurationSupport
的 Bean 时才启用。

上文说的 @EnableWebMvc 会引入 DelegatingWebMvcConfiguration 对象,而 DelegatingWebMvcConfiguration 类是 WebMvcConfigurationSupport 类的子类,所以 Spring MVC 的自动配置会失效。

建议

Spring MVC 自动配置失效后 application.properties 里一些 spring.* 开头配置就不会生效,不能方便的使用自动配置好的约定配置,同时很多开源组件
都依赖了这些配置,建议使用 Spring Boot 时尽量使用自动配置,只跟据需要作不同的配置。

实际上 WebMvcAutoConfiguration 的内部类 EnableWebMvcConfiguration 实现了和 @EnableWebMvc 一样的功能,自动配置开启的情况下依然
可以使用 WebMvcConfigurer 来进行自定义配置。

作者

Jakes Lee

发布于

2018-12-20

更新于

2021-11-18

许可协议

评论