NOTE

2.38 原理分析

1. spring-boot-starter-web预先导入的自动配置类 - @WebMvcAutoconfiguration WebMvcAutoConfigurationAdapter是Spring Boot开启web mvc自动配置的类,如下 - 里面有一个静态内部配置类, WebMvcAut

Java创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. spring-boot-starter-web预先导入的自动配置类

  • @WebMvcAutoconfiguration WebMvcAutoConfigurationAdapter是Spring Boot开启web mvc自动配置的类,如下
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
		WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {


		@Configuration
		@Import(EnableWebMvcConfiguration.class)//关键在于这个EnableWebMvcConfiguration
		@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
		//这个类继承了WebMvcConfigurerAdapter
		public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
			//...
		}
}	
  • 里面有一个静态内部配置类,WebMvcAutoConfigurationAdapter ta继承了WebMvcConfigurerAdapter :用于重写一些方法可以实现配置mvc。

  • 同时还导入了一个类EnableWebMvcConfiguration 这个类如下,继承了DelegatingWebMvcConfiguration【研究的重点】

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration 

2. 自定义配置生效的原理

2.1. 注入WebMvcConfigurerComposite和List

  • DelegatingWebMvcConfiguration用
@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 configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		this.configurers.configureContentNegotiation(configurer);
	}
	}

2.2. 使WebMvcConfigurerComposite调用WebMvcConfigurer的方法自定义配置spring-mvc

  • 这个类在setConfigurers方法使用了@Autowired注解,那么会把容器中所有的WebMvcConfigurer注入到参数的List<WebMvcConfigurer> configurers
  • 同时这个类还有个WebMvcConfigurerComposite属性,他是专门用于管理所有WebMvcConfigurer

我们以configureContentNegotiation方法为例,他会调用WebMvcConfigurerComposite的configureContentNegotiation方法,这个方法会遍历所有WebMvcConfigurer,调用他们的configureContentNegotiation方法 如下

class WebMvcConfigurerComposite implements WebMvcConfigurer {
	private final List<WebMvcConfigurer> delegates = new ArrayList<WebMvcConfigurer>();
	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		//把容器中所有的WebMvcConfigurer都调用一遍,包括我们的和SpringBoot的
		for (WebMvcConfigurer delegate : this.delegates) {
			delegate.configureContentNegotiation(configurer);
		}
	}
}

3. 使用@EnableWebMvc导致Spring Boot自动配置MVC失效的原因

首先看EnableWebMvcd导入的类DelegatingWebMvcConfiguration

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

这个DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport,也就相当于导入了WebMvcConfigurationSupport这个

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport

再看看mvc自动配置的类WebMvcAutoConfiguration

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
		WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//只有在WebMvcConfigurationSupport缺失的情况下这个类才生效
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration 

3.1. 条件注解导致预配置失效

  • 其实就是spring-boot-start-web预配置mvc的WebMvcAutoConfiguration这个类需要在 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//只有在WebMvcConfigurationSupport缺失的情况下这个类才生效
  • 如果我们配置了@EnableWebMvc,那么会导入DelegatingWebMvcConfiguration–继承了WebMvcConfigurationSupport
  • 两者冲突,所以自动配置失效

3.2. 如何添加自定义的mvc配置呢

@Configuration
//不能使用@EnableWebMvc,否则将是全面接管--即不再使用SpringBoot的自动配置
public class MyWebMvcConfig extends WebMvcConfigurerAdapter//继承WebMvcConfigurerAdapter,实现了WebMvcConfigurer接口
{
	//根据需要重写相应的方法即可,如此既可以扩展,又能使用默认实现
}

4. 参考