从官网API入手查看Sring Boot 为Spring MVC提供了那些配置,官方API链接如下:Spring Boot官方API。
下面是对API的原文内容进行翻译说明:
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
Spring Boot 提供了Spring mvc 需要工作运行的绝大部分应用。
The auto-configuration adds the following features on top of Spring’s defaults:
- Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans.- 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何
渲染(转发?重定向?)) - ContentNegotiatingViewResolver的作用:组合所有的视图解析器的;详解见文末代码片段1:
- 如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合进来;详解见文末代码片段1:
- 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何
- Support for serving static resources, including support for WebJars (see below).支持静态资源文件夹路径,webjars ,即可以通过maven添加依赖的方式添加静态资源文件
- Static
index.html
support.静态首页访问 - Custom
Favicon
support (see below). 网页导航栏小图标 - Automatic registration of(自动注册了)
-
Converter:转换器,应用场景:Controller层public String Hello(User user)接受页面传来的值进行user对象的构建,这时属性存在各种类型转换
Formatter
beans 格式化器,例如2018-10-1===Date;
-
@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格
式化的规则
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
}
//自定义格式化器的加载方法
@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);
}
}
private <T> Collection<T> getBeansOfType(Class<T> type) {
return this.beanFactory.getBeansOfType(type).values();
}
自己添加的格式化器转换器,我们只需要放在容器中即可
- Support for
HttpMessageConverters
(see below).- HttpMessageConverters:消息转换器,SpringMVC用来转换Http请求和响应的,例如:User对象返回到页面为Json数据
- HttpMessageConverters 是从容器中确定;获取所有的HttpMessageConverter;
自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中
(@Bean,@Component)
- Automatic registration of
MessageCodesResolver
(see below). 定义错误代码生成规则 - Automatic use of a
ConfigurableWebBindingInitializer
bean (see below).我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器)
org.springframework.boot.autoconfigure.web:web的所有自动场景;
5、如何修改SpringBoot的默认配置
模式:
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如
果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默
认的组合起来;
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration
class of type WebMvcConfigurerAdapter
, but without @EnableWebMvc
. If you wish to provide custom instances of RequestMappingHandlerMapping
, RequestMappingHandlerAdapter
or ExceptionHandlerExceptionResolver
you can declare a WebMvcRegistrationsAdapter
instance providing such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration
annotated with @EnableWebMvc
.
代码片段1:
/**
* WebMvcAutoConfiguration类
* 组合所有的视图解析器的,返回一个ContentNegotiatingViewResolver
*/
@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能看到视图解析器方法 resolveViewName-----------
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
if (requestedMediaTypes != null) {
//方法的核心:获取候选的视图对象,然后选择一个最适合(匹配)的视图对象
List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != null) {
return bestView;
}
}
if (this.useNotAcceptableStatusCode) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
}
return NOT_ACCEPTABLE_VIEW;
} else {
this.logger.debug("No acceptable view found; returning null");
return null;
}
}
//---------------------------------进一步查看 获取候选的视图对象的方法getCandidateViews------------------------
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
throws Exception {
List<View> candidateViews = new ArrayList<>();
//将对象的的所有视图解析器进行遍历从而获取所有视图
if (this.viewResolvers != null) {
Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
candidateViews.add(view);
}
for (MediaType requestedMediaType : requestedMediaTypes) {
List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
for (String extension : extensions) {
String viewNameWithExtension = viewName + '.' + extension;
view = viewResolver.resolveViewName(viewNameWithExtension, locale);
if (view != null) {
candidateViews.add(view);
}
}
}
}
}
if (!CollectionUtils.isEmpty(this.defaultViews)) {
candidateViews.addAll(this.defaultViews);
}
return candidateViews;
}
//-------------------------通过上面方法得出ContentNegotiatingViewResolver:组合所有的视图解析器的;-------------
//-------------------------但如何组合所有的试图解析器呢?见下面方法---------------------------------------------protected void initServletContext(ServletContext servletContext) {
//通过BeanFactoryUtils类工具将所有视图解析器对象获取
Collection<ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(),
ViewResolver.class).values();
if (this.viewResolvers == null) {
this.viewResolvers = new ArrayList<>(matchingBeans.size());
for (ViewResolver viewResolver : matchingBeans) {
if (this != viewResolver) {
this.viewResolvers.add(viewResolver);
}
}
}
else {
for (int i = 0; i < this.viewResolvers.size(); i++) {
ViewResolver vr = this.viewResolvers.get(i);
if (matchingBeans.contains(vr)) {
continue;
}
String name = vr.getClass().getName() + i;
obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(vr, name);
}
}
if (this.viewResolvers.isEmpty()) {
logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the " +
"'viewResolvers' property on the ContentNegotiatingViewResolver");
}
AnnotationAwareOrderComparator.sort(this.viewResolvers);
this.cnmFactoryBean.setServletContext(servletContext);
}