一、引言
用過SpringBoot
框架開發的應該都知道用 SpringBoot
開發非常方便,完全不需要自己配置,比手動用 Spring
搭建 SSM
框架,簡直就是不能比。當我們用 SpringBoot
開發 Web 項目時,只需要在項目中引入 spring-boot-starter-web
這個依賴,SpringMVC
的一整套東西就會被自動配置好,我們不用做其他複雜的配置。這就是SpringBoot
的一大特性——自動配置。
但在日常的工作開發中,由於項目環境比較複雜,可能有時候SpringBoot
自帶的默認配置不一定能滿足我們的需求,這種情況下,我們該怎麼辦呢?是不是要結合實際的項目來做一些自定義的配置。下面我們就來看看如何自定義 SpringMVC
的配置。
二、SpringMVC配置相關的類和註解
首先我們需要知道,跟自定義 SpringMVC
相關的類和註解主要有如下四個:
WebMvcConfigurerAdapter
WebMvcConfigurer // 接口
WebMvcConfigurationSupport
@EnableWebMvc
上面這四個,前三個中,兩個類一個接口,最後一個是註解。大家可以各個類中看一下,可以發現裏邊的方法看起來好像都類似,但是實際使用效果卻大不相同,因此很容易搞混,下面就來逐一介紹一下。
1、WebMvcConfigurerAdapter
首先來看 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
中定義的空方法一樣(是它的實現嘛~~),所以從用法上來說,基本上沒有差別,但各個版本之間的差別還是要注意一下。
2、WebMvcConfigurer
根據上面的介紹,我們知道 WebMvcConfigurer
是在 Spring Boot 2.x
中實現自定義配置的方案,不用做過多介紹了吧~~~~
3、WebMvcConfigurationSupport
前面兩個都好理解,還有一個 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
。
4、@EnableWebMvc
最後還有一個 @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
聯繫到一起了。