一、SpringBoot为SpringMVC提供的自动配置
1、SpringMVC的自动配置可参考官方文档:Spring Web MVC Framework
2、SpringBoot为SpringMVC提供的自动配置:参考类WebMvcAutoConfiguration
①Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans
SpringBoot为SpringMVC自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象——View,视图对象决定如何渲染,是转发还是重定向),SpringBoot通过ContentNegotiatingViewResolver组合所有的视图解析器(遍历容器中所有的视图解析器,并将这些视图解析器添加到viewResolvers中):
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);
}
}
}
if (this.viewResolvers.isEmpty()) {
this.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);
}
我们可以自己定制视图解析器,并将自定义的视图解析器添加到容器中:ContentNegotiatingViewResolver会自动的将其组合进来,例如:这里定义了一个静态内部类,使其实现ViewResolver接口
@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootWebApplication.class, args);
}
@Bean
public ViewResolver myViewResolver(){
return new MyViewResolver();
}
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
}
②Support for serving static resources, including support for WebJars (see below):SpringBoot支持静态资源文件夹路径,包括webjars
③Static index.html support:SpringBoot提供了静态首页访问
④Custom Favicon support (see below):自定义的 favicon.ico
⑤自动注册了Converter , GenericConverter , Formatter beans等转换器(转换器:页面传给后台的值都是文本类型的,后台拿到这些数据封装对象的时候可能需要进行类型转换,比如将"true"转换为Boolean类型,将“18”转为Integer类型等)和格式化器
@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在文件中配置日期格式化的规则
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
}
我们也可以自定义格式化器,方式类似于自定义视图解析器
⑥Support for HttpMessageConverters (see below):HTTP消息转换器,比如报文是对象还是JSON格式,也可以自定义
⑦Automatic registration of MessageCodesResolver (see below):定义错误代码生成规则
⑧Automatic use of a ConfigurableWebBindingInitializer bean (see below):自动将请求数据转化为JavaBean,可自定义
SpringBoot为SpringMVC做的所有自动配置都在org.springframework.boot.autoconfigure.web下
另外:
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.
二、如何修改SpringBoot的默认配置
模式:
1、SpringBoot在自动配置很多组件的时候,会先看容器中有没有用户自己配置的(@Bean、@Component)对应组件,如
果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(比如ViewResolver)SpringBoot会将用户配置的和默
认的组合起来:通过注解@ConditionalOnMissingBean来判断用户有没有自定义组件
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
2、在SpringBoot中会有非常多的XxxConfigurer帮助我们进行扩展配置
3、在SpringBoot中会有很多的XxxCustomizer帮助我们进行定制配置
三、扩展SpringMVC
比如:配置某些请求的视图或者某些请求的拦截器,在之前我们可以这么配置
<mvc:view-controller path="/hello" view-name="success"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean></bean>
</mvc:interceptor>
</mvc:interceptors>
现在我们可以自定义一个配置类:使用@Configuration标注,是WebMvcConfigurerAdapter类型,不能标注@EnableWebMvc,然后重写相应的方法即可,这样我们既保留了SpringBoot中所有的自动配置,也启用了我们扩展的配置
//通过重写WebMvcConfigurerAdapter的相应方法来扩展SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//对于一些简单的请求,比如不需要从后台获取数据的请求,可以采用这种方式直接返回页面,而不需要在Controller中写一些空方法
registry.addViewController("/bdm").setViewName("success");
}
}
扩展原理:
在做其他自动配置时会导入EnableWebMvcConfiguration:@Import(EnableWebMvcConfiguration.class)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
...
}
在该类中会将所有的WebMvcConfigurer组合起来:使容器中所有的WebMvcConfigurer一起起作用
//从容器中获取所有的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
//一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
...
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
...
}
四、全盘接管SpringgMVC
当我们不需要使用SpringBoot为SpringMVC提供的所有自动配置的时候,可以全面接管SpringMVC(不推荐这样做),只需要在配置类中添加@EnableWebMvc即可:
//通过重写WebMvcConfigurerAdapter的相应方法来扩展SpringMVC
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//对于一些简单的请求,比如不需要从后台获取数据的请求,可以采用这种方式直接返回页面,而不需要在Controller中写一些空方法
registry.addViewController("/bdm").setViewName("success");
}
}
原理:
SpringBoot中为SpringMVC提供的自动配置生效的前提是容器中不存在WebMvcConfigurationSupport:
@Configuration
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
...
}
一旦容器中存在了WebMvcConfigurationSupport,则WebMvcAutoConfiguration组件不会被加载到容器中,而@EnableWebMvc会@Import({DelegatingWebMvcConfiguration.class}),DelegatingWebMvcConfiguration继承自WebMvcConfigurationSupport,因此会导致WebMvcAutoConfiguration失效
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
WebMvcConfigurationSupport中只实现了SpringMVC最基本的功能,所以不推荐全面接管SpringMVC,除非项目中很少使用web模块