Spring Boot扩展、接管MVC

自从用了Spring Boot是否有一个感觉,以前MVC的配置都很少用到了,比如视图解析器,拦截器,过滤器等等,这也正是Spring Boot开箱即用的好处。

但是往往Spring Boot提供默认的配置不一定适合实际的需求,因此需要能够定制MVC的相关功能,这篇文章就介绍一下如何扩展和全面接管MVC。

如何扩展MVC?

在这里需要声明一个前提:配置类上没有标注 @EnableWebMvc 并且没有任何一个配置类继承了 WebMvcConfigurationSupport 。原因在后面。

步骤:

  1. 创建一个MVC的配置类,并且标注 @Configuration 注解。
  2. 实现 WebMvcConfigurer 这个接口,并且实现需要的方法。

WebMvcConfigurer 这个接口中定义了MVC相关的各种组件,比如拦截器,视图解析器等等的定制方法,需要定制什么功能,只需要实现即可。

在Spring Boot之前的版本还可以继承一个抽象类 WebMvcConfigurerAdapter ,不过在 2.3.4.RELEASE 这个 版本中被废弃了。

什么都不配置为什么依然能运行MVC相关的功能?

早期的SSM架构中想要搭建一个MVC其实挺复杂的,需要配置视图解析器,资源映射处理器, DispatcherServlet 等等才能正常运行。

Spring Boot的每一个 starter 都会有一个自动配置类,什么是自动配置类呢?自动配置类就是在Spring Boot项目启动的时候会自动加载的类,能够在启动期间就配置一些默认的配置。 WEB 模块的自动配置类是 WebMvcAutoConfiguration ,源码如下:

1
2
3
4
5
6
7
@AutoConfiguration(after = {DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
public class WebMvcAutoConfiguration {
}

WebMvcAutoConfiguration 这个配置类中还含有如下一个子配置类 WebMvcAutoConfigurationAdapter ,如 下:

1
2
3
4
5
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {}

WebMvcAutoConfigurationAdapter 这个子配置类实现了 WebMvcConfigurer 这个接口,这个正是MVC扩展接口,这个就很清楚了。自动配置类是在项目启动的时候就加载的,因此Spring Boot会在项目启动时加载 WebMvcAutoConfigurationAdapter 这个MVC扩展配置类,提前完成一些默认的配置(比如内置了默认的视图解析器,资源映射处理器等等),这也就是为什么没有配置什么MVC相关的东西依然能够运行。

如何全面接管MVC?【不推荐】

全面接管MVC是什么意思呢?全面接管的意思就是不需要Spring Boot自动配置,而是全部使用自定义的配置。

全面接管MVC其实很简单,只需要在配置类上添加一个 @EnableWebMvc 注解即可。

为什么@EnableWebMvc一个注解就能够全面接管MVC?

@EnableWebMvc 源码如下:

1
2
3
4
5
6
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

其实重要的就是这个@Import({DelegatingWebMvcConfiguration.class})注解了,Spring中的注解,快速导入一个配置类 ,源码如下:

1
2
3
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}

@EnableWebMvc 这个注解实际上就是导入了一个 WebMvcConfigurationSupport 子类型的配置类而已。

而WEB模块的自动配置类WebMvcAutoConfiguration有这么一行注解@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) ,这个注解的意思是IOC容器中没有指定的 Bean 这个配置才会生效。

总结一下,@EnableWebMvc导入了一个 WebMvcConfigurationSupport 类型的配置类,导致了自动配置类WebMvcAutoConfiguration标注的@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)判断为 false 了,从而自动配置类失效了。