NOTE
2.38 原理分析
1. spring-boot-starter-web预先导入的自动配置类 - @WebMvcAutoconfiguration WebMvcAutoConfigurationAdapter是Spring Boot开启web mvc自动配置的类,如下 - 里面有一个静态内部配置类, WebMvcAut
这是历史学习笔记,可能存在过时或不完整的理解。
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 {
//...
}
}
-
里面有一个静态内部配置类,
WebMvcAutoConfigurationAdapterta继承了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接口
{
//根据需要重写相应的方法即可,如此既可以扩展,又能使用默认实现
}