在SpringBoot 中如何自定義 SpringMVC 配置?

一、引言

用過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,如何搭建一個SpringWeb工程?),因爲本身就沒什麼自動化配置,所以可以使用繼承 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的出現。

三、小結

上面對 WebMvcConfigurerAdapterWebMvcConfigurerWebMvcConfigurationSupport、 @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聯繫到一起了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章