Spring MVC自动配置
Spring Boot为Spring MVC提供了自动配置,适用于大多数应用程序。
自动配置在Spring的默认值之上添加了以下功能:
包含ContentNegotiatingViewResolver和BeanNameViewResolver beans。
ContentNegotiatingViewResolver:组合所有视图解析器
支持提供静态资源,包括对WebJars的支持( 本文档稍后介绍))。
自动注册Converter,GenericConverter和Formatter
Converter:转换器
Formatter :格式化器 将页面带来的日期2017-12-12 ===》转到后台为Date
beans。
public void addFormatters(FormatterRegistry registry) {
Iterator var2 = this.getBeansOfType(Converter.class).iterator();
while(var2.hasNext()) {
Converter<?, ?> converter = (Converter)var2.next();
registry.addConverter(converter);
}
var2 = this.getBeansOfType(GenericConverter.class).iterator();
while(var2.hasNext()) {
GenericConverter converter = (GenericConverter)var2.next();
registry.addConverter(converter);
}
var2 = this.getBeansOfType(Formatter.class).iterator();
while(var2.hasNext()) {
Formatter<?> formatter = (Formatter)var2.next();
registry.addFormatter(formatter);
}
}
支持HttpMessageConverters:响应转换器 User ===》json
HttpMessageConverters
Spring MVC使用HttpMessageConverter接口转换HTTP请求和响应。明智的默认设置包含在开箱即用中。例如,对象可以自动转换为JSON(通过使用Jackson库)或XML(如果可用,使用Jackson XML扩展,或者如果Jackson XML扩展不是,则使用JAXB可用)。默认情况下,字符串以UTF-8编码。
如果您需要添加或自定义转换器,可以使用Spring Boot的HttpMessageConverters类,如下面的清单所示:
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;
@Configuration
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}
}
上下文中存在的任何HttpMessageConverter bean都将添加到转换器列表中。您也可以以相同的方式覆盖默认转换器。
自动注册MessageCodesResolver( 本文档后面部分)。
MessageCodesResolver
Spring MVC有一个生成错误代码的策略,用于从绑定错误中呈现错误消息:MessageCodesResolver。如果设置spring.mvc.message-codes-resolver.format属性PREFIX_ERROR_CODE或POSTFIX_ERROR_CODE,则Spring Boot会为您创建一个(请参阅枚举 DefaultMessageCodesResolver.Format
静态index.html支持。
自定义Favicon支持(本文档稍后介绍)
自动使用ConfigurableWebBindingInitializer bean(本文 后面会介绍)。
静态内容
默认情况下,Spring Boot从类路径中的/static(或/public或/resources或/META-INF/resources)目录或ServletContext的根目录中提供静态内容。它使用来自Spring MVC的ResourceHttpRequestHandler,以便您可以通过添加自己的WebMvcConfigurer并覆盖addResourceHandlers方法来修改该行为。
默认情况下,资源映射到/** ,
但您可以使用 spring.mvc.static-path-pattern 属性对其进行调整。例如,将所有资源重新定位到/resources/**
可以实现如下:
spring.mvc.static-path-pattern=/resources/**
您还可以使用spring.resources.static-locations属性自定义静态资源位置(将默认值替换为目录位置列表)。根Servlet上下文路径"/"也会自动添加为位置。
@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(
name = {"viewResolver"},
value = {ContentNegotiatingViewResolver.class}
)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
resolver.setOrder(-2147483648);
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);
}
}
}
如果你想保留Spring Boot MVC功能,并且你想添加额外的 MVC配置(拦截器,格式化程序,视图控制器和其他功能),你可以添加自己的
@Configuration类WebMvcConfigurer类但不能标注@EnableWebMvc。如果您希望提供RequestMappingHandlerMapping,RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义实例,则可以声明WebMvcRegistrationsAdapter实例以提供此类组件。
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override public void addViewControllers(ViewControllerRegistry registry) {
//浏览器发送 /atguigu 请求来到 success
registry.addViewController("/atguigu").setViewName("success");
}
}
原理:
@Configuration
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
EnableWebMvcConfiguration.class 内容如下
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
private final ResourceProperties resourceProperties;
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final WebMvcRegistrations mvcRegistrations;
private ResourceLoader resourceLoader;
}
DelegatingWebMvcConfiguration 内容如下
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
public DelegatingWebMvcConfiguration() {
}
从容器中获取所有的WebMvcConfigur
@Autowired(
required = false
)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
}
addViewControllers(registry); 参考实现
public void addViewControllers(ViewControllerRegistry registry) {
Iterator var2 = this.delegates.iterator();
拿到所有的 WebMvcConfigurer
while(var2.hasNext()) {
WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
delegate.addViewControllers(registry);
}
}
如果您想完全控制Spring MVC,可以添加自己的@Configuration注释@EnableWebMvc。所有的内容都是自己配置
为啥一配置@EnableWebMvc springmvc的自动配置就会失效呢?
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
DelegatingWebMvcConfiguration.class
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
webmvc 没有这个组件 WebMvcConfigurationSupport.class,下面的配置文件才会生效
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
DelegatingWebMvcConfiguration.class 这个却恰恰继承了 WebMvcConfigurationSupport,如果配置@EnableWebMvc这个注解,自动配置就会失效
@Configuration
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
webmvc 没有这个组件 WebMvcConfigurationSupport.class,下面的配置文件才会生效
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})