擴充套件、接管MVC都不會,還會用Spring Boot?

愛撒謊的男孩發表於2020-10-13

持續原創輸出,點選上方藍字關注我

目錄

  • 前言
  • Spring Boot 版本
  • 如何擴充套件MVC?
  • 如何自定義一個攔截器?
  • 什麼都不配置為什麼依然能執行MVC相關的功能?
  • 如何全面接管MVC?【不推薦】
  • 為什麼@EnableWebMvc一個註解就能夠全面接管MVC?
  • Spring Boot相關資料
  • 總結

前言

自從用了Spring Boot是否有一個感覺,以前MVC的配置都很少用到了,比如檢視解析器,攔截器,過濾器等等,這也正是Spring Boot好處之一。

但是往往Spring Boot提供預設的配置不一定適合實際的需求,因此需要能夠定製MVC的相關功能,這篇文章就介紹一下如何擴充套件和全面接管MVC。

Spring Boot 版本

本文基於的Spring Boot的版本是2.3.4.RELEASE

如何擴充套件MVC?

在這裡需要宣告一個前提:配置類上沒有標註@EnableWebMvc並且沒有任何一個配置類繼承了WebMvcConfigurationSupport。至於具體原因,下文會詳細解釋。

擴充套件MVC其實很簡單,只需要以下步驟

  1. 建立一個MVC的配置類,並且標註@Configuration註解。
  2. 實現WebMvcConfigurer這個介面,並且實現需要的方法。

WebMvcConfigurer這個介面中定義了MVC相關的各種元件,比如攔截器,檢視解析器等等的定製方法,需要定製什麼功能,只需要實現即可。

在Spring Boot之前的版本還可以繼承一個抽象類WebMvcConfigurerAdapter,不過在2.3.4.RELEASE這個版本中被廢棄了,如下:

@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {}

舉個例子:現在要新增一個攔截器,使其在Spring Boot中生效,此時就可以在MVC的配置類重寫addInterceptors()方法,如下:

/**
 * MVC擴充套件的配置類,實現WebMvcConfigurer介面
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private RepeatSubmitInterceptor repeatSubmitInterceptor;

    /**
     * 重寫addInterceptors方法,注入自定義的攔截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(repeatSubmitInterceptor).excludePathPatterns("/error");
    }
}

操作很簡單,除了攔截器,還可以定製檢視解析,資源對映處理器等等相關的功能,和Spring MVC很類似,只不過Spring MVC是在XML檔案中配置,Spring Boot是在配置類中配置而已。

什麼都不配置為什麼依然能執行MVC相關的功能?

早期的SSM架構中想要搭建一個MVC其實挺複雜的,需要配置檢視解析器,資源對映處理器,DispatcherServlet等等才能正常執行,但是為什麼Spring Boot僅僅是新增一個WEB模組依賴即能正常執行呢?依賴如下:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency> 

其實這已經涉及到了Spring Boot高階的知識點了,在這裡就簡單的說一下,Spring Boot的每一個starter都會有一個自動配置類,什麼是自動配置類呢?自動配置類就是在Spring Boot專案啟動的時候會自動載入的類,能夠在啟動期間就配置一些預設的配置WEB模組的自動配置類是WebMvcAutoConfiguration

WebMvcAutoConfiguration這個配置類中還含有如下一個子配置類WebMvcAutoConfigurationAdapter,如下:

@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,導致自動配置類失效
 */
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private RepeatSubmitInterceptor repeatSubmitInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //新增攔截器
        registry.addInterceptor(repeatSubmitInterceptor).excludePathPatterns("/error");
    }
}

一個註解就能全面介面MVC,是不是很爽,不過,不建議使用。

為什麼@EnableWebMvc一個註解就能夠全面接管MVC?

what???為什麼呢?上面剛說過自動配置類WebMvcAutoConfiguration會在專案啟動期間載入一些預設的配置,這會怎麼新增一個@EnableWebMvc註解就不行了呢?

其實很簡單,@EnableWebMvc原始碼如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

其實重要的就是這個@Import(DelegatingWebMvcConfiguration.class)註解了,Spring中的註解,快速匯入一個配置類DelegatingWebMvcConfiguration,原始碼如下:

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

明白了,@EnableWebMvc這個註解實際上就是匯入了一個WebMvcConfigurationSupport子型別的配置類而已

而WEB模組的自動配置類有這麼一行註解@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),原始碼如下:

@Configuration(proxyBeanMethods = false)
@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 {

這個註解@ConditionalOnMissingBean什麼意思呢?簡單的說就是IOC容器中沒有指定的Bean這個配置才會生效。

一切都已經揭曉了,@EnableWebMvc匯入了一個WebMvcConfigurationSupport型別的配置類,導致了自動配置類WebMvcAutoConfiguration標註的@@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)判斷為false了,從而自動配置類失效了。

總結

擴充套件和全面接管MVC都很簡單,但是不推薦全面接管MVC,一旦全面接管了,WEb模組的這個starter將沒有任何意義,一些全域性配置檔案中與MVC相關的配置也將會失效。

相關文章