浅析 Spring 和 SpringBoot 对 web MVC 配置的区别及其原理

浅析 Spring 和 SpringBoot 对 web MVC 配置的区别及其原理

  • 前言
  • Spring
    • EnableWebMvc
    • DelegatingWebMvcConfiguration
    • WebMvcConfigurer
    • 小结
  • Spring Boot
    • WebMvcAutoConfiguration
    • 小结
  • 总结

前言

众所周知,SpringSpringBootweb MVC 的推荐配置方式是有所不同的

其实,对大多数模块或者三应用来说,与 Spring 的集成通常是这样一种模式:

  1. Spring 基于模块的功能或者三方应用的 API 提供对应的 bean 组件
  2. 由使用者(我们)来根据具体的场景注册对应的 bean

SpringBoot 是这样的:

  1. 提供了强大的自动装配,可以理解为提供了一套理论上的最佳实践
  2. 同时更可贵也必须的是允许使用者的自定义覆盖
  3. 这也正是 SpringBoot 更加流行的原因之一(约定大于配置)

web MVC 的配置来说,也可以理解为这种模式,但也有所不同,本文简单的聊一下个人对这些内容的理解

Spring

EnableWebMvc

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
  • EnableXXXSpring 常用的模块化设计模式
  • 引入了配置类 DelegatingWebMvcConfiguration

DelegatingWebMvcConfiguration

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

	// 收集容器中所有的 WebMvcConfigurer
	@Autowired(required = false)
	public void setConfigurers(List<WebMvcConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.configurers.addWebMvcConfigurers(configurers);
		}
	}

	// 重写 WebMvcConfigurationSupport 的部分方法,把它们的实现委托到 List configurers 上
	@Override
	protected void configurePathMatch(PathMatchConfigurer configurer) {
		this.configurers.configurePathMatch(configurer);
	}

	// ...

}
  • 首先它是一个 WebMvcConfigurationSupportWebMvcConfigurationSupport 是提供 Spring MVC 核心组件的配置类,它允许子类在它的基础上解析自定义拓展,而这个任务就由 DelegatingWebMvcConfiguration 完成
  • DelegatingWebMvcConfigurationWebMvcConfigurerComposite 来收集容器中所有的 WebMvcConfigurer,转而把对 WebMvcConfigurationSupport 组件方法的拓展委托给这些 WebMvcConfigurer,比如方法 configurePathMatch

WebMvcConfigurer

public interface WebMvcConfigurer {

	/**
	 * 自定义配置 PathMatchConfigurer
	 */
	default void configurePathMatch(PathMatchConfigurer configurer) {
	}

	// ...

}
  • 因此,我们覆盖、拓展 Spring 默认提供的 MVC 组件,实现该接口并复写对应方法即可
  • 一般我们使用主配置类实现该接口,当然也可以提供多个 WebMvcConfigurer
  • 当然,它的拓展是有限的,毕竟依托于 WebMvcConfigurationSupport 暴露出来的方法,因此更加全面细粒度的控制则可以直接继承 WebMvcConfigurationSupport,但这一般没有必要

小结

其实我理解这类似于一种 Spring 自己的自动装配机制:提供一组最佳实践的组件并允许使用者覆盖,覆盖模式就是复写暴露出来的对应方法

Spring Boot

浅析 Spring 和 SpringBoot 对 web MVC 配置的区别及其原理_第1张图片
Spring Boot 使用的是经典的自动装配模式

WebMvcAutoConfiguration

@Configuration(proxyBeanMethods = false)
// ...
public class WebMvcAutoConfiguration {

	// ...

	@Configuration(proxyBeanMethods = false)
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {

		// ...

	}

	@Configuration(proxyBeanMethods = false)
	@EnableConfigurationProperties(WebProperties.class)
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

		// ...

	}

	// ...

}
  • 该装配类的整体结构如上,其中
  • WebMvcAutoConfigurationAdapter,该配置类是一个 WebMvcConfigurer,相当于 Spring Boot 自己提供了一个 WebMvcConfigurer,同时 import 了一个 EnableWebMvcConfiguration
  • EnableWebMvcConfiguration 是一个 DelegatingWebMvcConfiguration,相当于 Spring Boot 帮我们完成了在 Spring 中相当于 @EnableWebMvc 的工作并进行了拓展

小结

  • Spring Boot 相当于自己同时提供了 DelegatingWebMvcConfigurationWebMvcConfigurer,这也正符合 Spring Boot 的理念
  • 对应可配置的属性则是通过 ConfigurationProperties 暴露出去

总结

因此,我们在基于 Spring Boot 使用 web MVC 时一般不建议使用 @EnableWebMvc,因为这相当于引入了 Spring 提供的 DelegatingWebMvcConfiguration,两者的组件必然会发生优先级的冲突

具体组件冲突取决于 @ConditionalOnXXX @Primary 等注解,就不
一一解析了

你可能感兴趣的:(#,Spring,Web,MVC,spring)