- Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans.
自动配置了视图解析器。
在 WebMvcAutoConfiguration 里直接搜索这个类。
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver",
value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(
beanFactory.getBean(ContentNegotiationManager.class));
// ContentNegotiatingViewResolver uses all the other view resolvers to locate
// a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
进入 ContentNegotiatingViewResolver 类,找到初始化方法:
protected void initServletContext(ServletContext servletContext) {
Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
ViewResolver viewResolver;
if (this.viewResolvers == null) {
this.viewResolvers = new ArrayList(matchingBeans.size());
Iterator var3 = matchingBeans.iterator();
while(var3.hasNext()) {
viewResolver = (ViewResolver)var3.next();
if (this != viewResolver) {
this.viewResolvers.add(viewResolver);
}
}
} else {
for(int i = 0; i < this.viewResolvers.size(); ++i) {
viewResolver = (ViewResolver)this.viewResolvers.get(i);
if (!matchingBeans.contains(viewResolver)) {
String name = viewResolver.getClass().getName() + i;
this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name);
}
}
}
AnnotationAwareOrderComparator.sort(this.viewResolvers);
this.cnmFactoryBean.setServletContext(servletContext);
}
发现它把项目里所有的视图解析器都组合到一起。
那么我们就可以写自己的视图解析器,ContentNegotiatingViewResolver 会自动组合起来。在解析视图的时候,会遍历视图解析器进行解析,直到找到合适的视图解析器。
- Support for serving static resources, including support for WebJars (covered later in this document)).
- Static
index.html
support. - Custom
Favicon
support (covered later in this document).
这三个是处理静态资源的。原理呢,就是通过一个静态资源映射。
- Automatic registration of
Converter
,GenericConverter
, andFormatter
beans.
自动注册了转换器、格式化器。比如,日期格式化,封装对象等等。
@Override
public void addFormatters(FormatterRegistry registry) {
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
registry.addConverter(converter);
}
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
registry.addConverter(converter);
}
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
registry.addFormatter(formatter);
}
}
- Support for
HttpMessageConverters
(covered later in this document).
httpMessage 转换器。在原生版本的 Spring mvc,讲求的是一个 viewModel,交给视图解析器去解析,现在使用转换器,把数据转成 json。
进入这个类一看:
public HttpMessageConverters(boolean addDefaultConverters,
Collection<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> combined = getCombinedConverters(converters,
addDefaultConverters ? getDefaultConverters() : Collections.emptyList());
combined = postProcessConverters(combined);
this.converters = Collections.unmodifiableList(combined);
}
它也把容器中所有的 HttpMessageConverter 给组合到一起,到处都是这种思想,这样方便我们定义自己的转换器。
- Automatic registration of
MessageCodesResolver
(covered later in this document).
错误代码装换器。
- Automatic use of a
ConfigurableWebBindingInitializer
bean (covered later in this document).
@Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
try {
return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
}
catch (NoSuchBeanDefinitionException ex) {
return super.getConfigurableWebBindingInitializer();
}
}
从容器中拿,拿不到,就调用父类的方法。就是这样的写法,才使得 Spring Boot 可以自动配置,同时支持自定义。
public void initBinder(WebDataBinder binder) {
binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
if (this.directFieldAccess) {
binder.initDirectFieldAccess();
}
if (this.messageCodesResolver != null) {
binder.setMessageCodesResolver(this.messageCodesResolver);
}
if (this.bindingErrorProcessor != null) {
binder.setBindingErrorProcessor(this.bindingErrorProcessor);
}
if (this.validator != null && binder.getTarget() != null && this.validator.supports(binder.getTarget().getClass())) {
binder.setValidator(this.validator);
}
if (this.conversionService != null) {
binder.setConversionService(this.conversionService);
}
if (this.propertyEditorRegistrars != null) {
PropertyEditorRegistrar[] var2 = this.propertyEditorRegistrars;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
PropertyEditorRegistrar propertyEditorRegistrar = var2[var4];
propertyEditorRegistrar.registerCustomEditors(binder);
}
}
}
数据绑定器,就是把前端传来的数据,转换、绑定到我们控制层方法设置的参数上。
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own
@Configuration
class of typeWebMvcConfigurer
but without@EnableWebMvc
. If you wish to provide custom instances ofRequestMappingHandlerMapping
,RequestMappingHandlerAdapter
, orExceptionHandlerExceptionResolver
, you can declare aWebMvcRegistrationsAdapter
instance to provide such components.
想使用现有特性,也想加一些其他的功能,可以自定义 WebMvcRegistrationsAdapter 配置类,但是要取消 @EnableWebMvc 注解。
如果加了 @EnableWebMvc 注解,Spring Boot 自动配置的部分就失效了。
- @EnableWebMvc的核心, 导入一个DelegatingWebMvcConfiguration类。
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
2)、 这个配置类继承了 WebMvcConfigurationSupport
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3)、而 Spring Boot 自动配置要生效,需要没有 WebMvcConfigurationSupport 这个类,所以自动配置就不会生效了。
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
4)、@EnableWebMvc 将 WebMvcConfigurationSupport 组件导入进来;
5)、导入的 WebMvcConfigurationSupport 只是 SpringMVC 最基本的功能;
总结:
1、在自动配置组件的时候,会先判断是否已经存在对应的组件,如果存在,则加载,不存在,则生成默认的。如果允许多个组件,比如视图解析器,那就组合到一起。我们可以定义自己的组件,Spring Boot 帮助我们进行扩展配置。
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置。
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置。