概述
DelegatingWebMvcConfiguration
是对Spring MVC
进行配置的一个代理类。它结合缺省配置和用户配置定义Spring MVC
运行时最终使用的配置。
DelegatingWebMvcConfiguration
继承自WebMvcConfigurationSupport
。而WebMvcConfigurationSupport
为Spring MVC
提供缺省配置。这就是上面所提到的缺省配置。
DelegatingWebMvcConfiguration
又会被注入一组WebMvcConfigurer
,顾名思义,这是一组"Spring MVC
配置器"。这组配置器由开发人员或者框架某一部分提供,是接口WebMvcConfigurer
的实现类,按照Spring
的建议,通常也是一个配置类,也就是使用了注解@Configuration
的类。这组WebMvcConfigurer
就是上面提到的用户配置。
DelegatingWebMvcConfiguration
本身使用了注解@Configuration
,所以它是一个配置类,因此它也会被作为一个单例bean
注册到容器和被容器注入相应的依赖。WebMvcConfigurer
注入到DelegatingWebMvcConfiguration
正是因为他是一个bean
并且在方法void setConfigurers(List<WebMvcConfigurer> configurers)
使用了注解@Autowired(required = false)
。
WebMvcConfigurationSupport
提供缺省配置的主要方式是定义一组bean
供Spring MVC
在运行时使用,而这些bean
定义方法所用的配置原料供应方法给子类保留了可覆盖的回调方法用于定制化(这些定制化回调方法正好通过接口WebMvcConfigurer
抽象建模)。WebMvcConfigurationSupport
为这些用于定制的回调方法提供了缺省实现(比如空方法),而DelegatingWebMvcConfiguration
则覆盖了这些方法,使用所注入的WebMvcConfigurers
对相应的配置原料进行定制从而起到定制整个Spring MVC
配置的作用。
注解@EnableWebMvc
的作用其实就是引入一个DelegatingWebMvcConfiguration
用于配置Spring MVC
。而通常,我们正式使用注解@EnableWebMvc
在某个实现了WebMvcConfigurer
的配置类上来配置Spring MVC
的,如下所示 :
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
// ...
}
源代码解析
package org.springframework.web.servlet.config.annotation;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
/**
* A subclass of WebMvcConfigurationSupport that detects and delegates
* to all beans of type WebMvcConfigurer allowing them to customize the
* configuration provided by WebMvcConfigurationSupport. This is the
* class actually imported by @EnableWebMvc.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// WebMvcConfigurerComposite 其实就是对多个 WebMvcConfigurer 的一个组合,
// 从命名就可以看出这一点
// WebMvcConfigurerComposite 自身也实现了接口 WebMvcConfigurer,
// 问 : 为什么要组合多个 WebMvcConfigurer 然后自己又实现该接口 ?
// 答 : 这么做的主要目的是在配置时简化逻辑。调用者对 WebMvcConfigurerComposite
// 可以当作一个 WebMvcConfigurer 来使用,而对它的每个方法的调用都又会传导到
// 它所包含的各个 WebMvcConfigurer 。
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
// 注入一组WebMvcConfigurer,这些WebMvcConfigurer由开发人员提供,或者框架其他部分提供,已经
// 以bean的方式注入到容器中
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
// 以下各个方法都是对WebMvcConfigurationSupport提供的配置原材料定制回调方法的覆盖实现,
// 对这些方法的调用最终都转化成了对configurers的方法调用,从而实现了定制化缺省Spring MVC
// 配置的作用
@Override
protected void configurePathMatch(PathMatchConfigurer configurer) {
this.configurers.configurePathMatch(configurer);
}
@Override
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
this.configurers.configureContentNegotiation(configurer);
}
@Override
protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
this.configurers.configureAsyncSupport(configurer);
}
@Override
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
this.configurers.configureDefaultServletHandling(configurer);
}
@Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
this.configurers.addResourceHandlers(registry);
}
@Override
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
@Override
protected void configureViewResolvers(ViewResolverRegistry registry) {
this.configurers.configureViewResolvers(registry);
}
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
this.configurers.addArgumentResolvers(argumentResolvers);
}
@Override
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
this.configurers.addReturnValueHandlers(returnValueHandlers);
}
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.configurers.configureMessageConverters(converters);
}
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
this.configurers.extendMessageConverters(converters);
}
@Override
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.configurers.configureHandlerExceptionResolvers(exceptionResolvers);
}
@Override
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.configurers.extendHandlerExceptionResolvers(exceptionResolvers);
}
@Override
@Nullable
protected Validator getValidator() {
return this.configurers.getValidator();
}
@Override
@Nullable
protected MessageCodesResolver getMessageCodesResolver() {
return this.configurers.getMessageCodesResolver();
}
}