用过SpringBoot
框架开发的应该都知道用 SpringBoot
开发非常方便,完全不需要自己配置,比手动用 Spring
搭建 SSM
框架,简直就是不能比。当我们用 SpringBoot
开发 Web 项目时,只需要在项目中引入 spring-boot-starter-web
这个依赖,SpringMVC
的一整套东西就会被自动配置好,我们不用做其他复杂的配置。这就是SpringBoot
的一大特性——自动配置。
但在日常的工作开发中,由于项目环境比较复杂,可能有时候SpringBoot
自带的默认配置不一定能满足我们的需求,这种情况下,我们该怎么办呢?是不是要结合实际的项目来做一些自定义的配置。下面我们就来看看如何自定义 SpringMVC
的配置。
首先我们需要知道,跟自定义 SpringMVC
相关的类和注解主要有如下四个:
WebMvcConfigurerAdapter
WebMvcConfigurer // 接口
WebMvcConfigurationSupport
@EnableWebMvc
上面这四个,前三个中,两个类一个接口,最后一个是注解。大家可以各个类中看一下,可以发现里边的方法看起来好像都类似,但是实际使用效果却大不相同,因此很容易搞混,下面就来逐一介绍一下。
首先来看 WebMvcConfigurerAdapter
,这个类出现在Spring 3.1
的版本中,如果你用的是 SpringBoot 1.x
开发项目,我们在自定义 SpringMVC
时需要继承这个抽象类,这个抽象类本身是实现了 WebMvcConfigurer
接口,然后抽象类里边都是空方法,下面看一下这个类的声明:
/**
* An implementation of {@link WebMvcConfigurer} with empty methods allowing
* subclasses to override only the methods they're interested in.
* @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
* possible by a Java 8 baseline) and can be implemented directly without the
* need for this adapter
*/
@Deprecated // 标记已经过时了
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
//各种 SpringMVC 配置的方法,而且都是空方法
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer
configurer) {
}
......
}
我们来关注一下这个类上面的注释,对于这个类的说明是不是一目了然。同时我们也看到,从 Spring5
开始,由于我们要使用 Java8
,而 Java8
中的接口允许存在 default
方法,因此官方建议我们直接实现 WebMvcConfigurer
接口,而不是继承 WebMvcConfigurerAdapter
。
也就是说,如果你的项目是用 Spring Boot 1.x
版本,如果需要自定义SpringMVC
配置,直接继承 WebMvcConfigurerAdapter
类即可。
这里多说一句,之前有个小伙伴从github上下载了我的样例代码,死活运行不起来,后来我让他把报错信息发我看一下,就是这个地方的原因。我的样例用的是SpringBoot 2.0.x
,而他的环境用的是SpringBoot 1.0.x
,从 Spring Boot 1.x
切换到 Spring Boot 2.x
,需要把继承类改成实现接口。由于WebMvcConfigurer
是一个接口,接口中的方法和 WebMvcConfigurerAdapter
中定义的空方法一样(是它的实现嘛~~),所以从用法上来说,基本上没有差别,但各个版本之间的差别还是要注意一下。
根据上面的介绍,我们知道 WebMvcConfigurer
是在 Spring Boot 2.x
中实现自定义配置的方案,不用做过多介绍了吧~~~~
前面两个都好理解,还有一个 WebMvcConfigurationSupport
,这个类又是干什么用的呢?
不知道大家有没有用过Servlet3.0
和纯注解的方式来搭建过SSM框架,如果没有的话,可以自己尝试一下,会让你受益匪浅。
当我们用纯注解来搭建SSM
框架时,在自定义SpringMVC
配置的时候,就是通过继承 WebMvcConfigurationSupport
类来实现的。在 WebMvcConfigurationSupport
类中,提供了用 Java
配置 SpringMVC
所需要的所有方法。下面来看一下这个方法的摘要:
如果你看过上面两个类的源码的话,再看这个类,肯定觉得眼熟,你再仔细看一下,这里的方法是不是和前面两个类中的方法基本是一样的???
在这里首先大家需要明确的是,WebMvcConfigurationSupport
类本身是没有问题的,我们自定义SpringMVC
的配置是可以通过继承 WebMvcConfigurationSupport
来实现的。但是继承 WebMvcConfigurationSupport
这种操作一般只在 Java
配置的 SSM
项目中使用,SpringBoot
中基本上不会这么写,为什么呢?
因为在 SpringBoot
中,SpringMVC
相关的自动化配置是在 WebMvcAutoConfiguration
这个配置类中实现的,那么我们来看看这个配置类的生效条件:
@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 {
}
我们从这个类的注解中可以看到,SpringBoot
自动配置的生效条件有一个就是:当不存在 WebMvcConfigurationSupport
的实例时,这个自动化配置才会生效。因此,如果我们在 SpringBoot
中自定义 SpringMVC
配置时选择了继承 WebMvcConfigurationSupport
,就会导致 SpringBoot
中 默认的SpringMVC
的自动化配置失效。
SpringBoot
给我们提供了很多自动化配置,大部分时间里,当我们需要修改这些配置的时候,并不是要全盘否定 SpringBoot
提供的自动化配置,我们可能只是针对某一个配置做出修改,其他的配置还是按照 SpringBoot
默认的自动化配置来,而继承 WebMvcConfigurationSupport
来实现对 SpringMVC
的配置会导致所有的 SpringMVC
自动化配置失效,因此,一般情况下我们不选择继承WebMvcConfigurationSupport
。
但我们在用 Java
搭建的 SSM
项目中(不用SpringBoot
,如何搭建一个Spring
的Web
工程?),因为本身就没什么自动化配置,所以可以使用继承 WebMvcConfigurationSupport
。
最后还有一个 @EnableWebMvc
注解,这个注解很好理解,它的作用就是在SpringBoot
中启用WebMvcConfigurationSupport
。
我们来看看这个注解的定义:
/**
* Adding this annotation to an {@code @Configuration} class imports
* the Spring MVC configuration from {@link WebMvcConfigurationSupport}, e.g.:
* /
可以看到,加了这个注解,就会自动导入 WebMvcConfigurationSupport
,所以在 SpringBoot
中,我们也不建议使用 @EnableWebMvc
注解,因为它一样会导致 SpringBoot
中的 SpringMVC
自动化配置失效。因为WebMvcAutoConfiguration
生效的条件就是不能有WebMvcConfigurationSupport
的出现。
上面对 WebMvcConfigurerAdapter
、WebMvcConfigurer
、WebMvcConfigurationSupport
、 @EnableWebMvc
这四个知识做了详细的介绍。下面来对它们做一下总结:
Spring Boot 1.x
中,自定义SpringMVC
配置可以通过继承 WebMvcConfigurerAdapter
来实现。
Spring Boot 2.x
中,自定义SpringMVC
配置可以通过实现 WebMvcConfigurer
接口来完成。
如果在 SpringBoot
中使用继承 WebMvcConfigurationSupport
来实现自定义 SpringMVC
配置,
或者在 SpringBoot
中使用了 @EnableWebMvc
注解,都会导致 SpringBoot
中默认配置的 SpringMVC
自动化配置失效。
在纯 Java 配置的 SSM 环境中,如果我们要自定义 SpringMVC
配置,有两种办法,第一种就是直接继承自 WebMvcConfigurationSupport
来完成 SpringMVC
配置,还有一种方案就是实现 WebMvcConfigurer
接口来完成自定义 SpringMVC
配置,如果使用后一种方式,我们需要给 SpringMVC
的配置类上额外添加 @EnableWebMvc
注解,表示启用 WebMvcConfigurationSupport
,这样配置才会生效。换句话说,在纯 Java 配置的 SSM 中,如果你需要自定义 SpringMVC
配置,你离不开 WebMvcConfigurationSupport
,所以在这种情况下建议通过继承 WebMvcConfigurationSupport
来实现自动化配置。
这里多解释一下:在纯Java配置的SSM中,实现 WebMvcConfigurer
接口来完成自定义 SpringMVC
配置,为什么一定要开启@EnableWebMvc注解呢?
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
来看一下这个注解,使用这个注解,就是往Spring容器
中添加了DelegatingWebMvcConfiguration
这个Bean。再看一下DelegatingWebMvcConfiguration
这个类,有这样一个属性WebMvcConfigurerComposite
,维护着WebMvcConfigurer
的集合,有点类似组合模式。初始化DelegatingWebMvcConfiguration
时如果发现了WebMvcConfigurer
的实现类,就注入到WebMvcConfigurerComposite
中,这样就把我们实现了WebMvcConfigurer
的类和@EnableWebMvc
联系到一起了。