Spring注解@EnableWebMvc使用坑點解析


通過注解的方式來進行Spring4 MVC開發時,我們都會在配置文件中加入<mvc:annotation-driven/>標簽,這個配置會自動注冊了一個 RequestMappingHandlerMapping、一個RequestMappingHandlerAdapter、以及一個ExceptionHandlerExceptionResolver 以支持使用注解Controller的注解方法(如@RequestMapping、@ExceptionHandler)來處理request,並開啟一系列默認功能設置。

<!-- 開啟SpringMVC注解模式 -->
<!-- 提供一系列功能:數據綁定,數字和日期format @NumberFormat,
@DataTimeFormat,xml/json默認讀寫支持-->
<mvc:annotation-driven/>
1
2
3
4
如果沒有配置<mvc:annotation-driven/>,org.springframework.web.servlet.DispatcherServlet無法找到控制器並把請求分發到控制器。添加上<mvc:annotation-driven/>后,請求會被相應的Controller處理。然而這時訪問靜態資源可能就不好使了,怎么辦?一般可以使用 <mvc:default-servlet-handler />這個標簽

<!-- 靜態資源默認servlet配置
1.加入對靜態資源的處理:js/gif
2.允許使用"/"做整體映射
-->
<mvc:default-servlet-handler />
1
2
3
4
5
所以這兩個標簽一般放在一起使用。

在Spring Boot中使用@EnableWebMvc也可能遇到類似的問題,@EnableWebMvc是使用注解方式快捷配置Spring Webmvc的一個注解。在使用時你可能會遇到以下問題:

Spring Boot在application文件中的配置失效
在Spring Boot的自定義配置類加上@EnableWebMvc后,發現自動配置的靜態資源路徑(classpath:/META/resources/,classpath:/resources/,classpath:/static/,classpath:/public/)資源無法訪問。
通過查看@EnableWebMvc的源碼,可以發現該注解就是為了引入一個DelegatingWebMvcConfiguration 配置類,而DelegatingWebMvcConfiguration又繼承於WebMvcConfigurationSupport。也就是說,如果我們使用@EnableWebMvc就相當於導入了WebMvcConfigurationSupport類,這個時候,Spring Boot的自動裝配就不會發生了,我們能用的,只有WebMvcConfigurationSupport提供的若干個配置。其實不使用@EnableWebMvc注解也是可以實現配置Webmvc,只需要將配置類繼承於WebMvcConfigurationSupport類即可。

當使用@EnableWebMvc時,加載的是WebMvcConfigurationSupport中的配置項。

當不使用@EnableWebMvc時,使用的是WebMvcAutoConfiguration引入的配置項。

查看一下WebMvcAutoConfiguration 的源碼:

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
...
}
1
2
3
4
5
6
7
8
9
10
可以看到自動配置類 WebMvcAutoConfiguration 上有條件注解

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
1
這個注解的意思是在項目類路徑中缺少 WebMvcConfigurationSupport類型的bean時改自動配置類才會生效。

有時候我們需要自己定制一些項目的設置,可以有以下幾種使用方式:

@EnableWebMvc+extends WebMvcConfigurationAdapter,在擴展的類中重寫父類的方法即可,這種方式會屏蔽springboot的@EnableAutoConfiguration中的設置

extends WebMvcConfigurationSupport,在擴展的類中重寫父類的方法即可,這種方式會屏蔽springboot的@EnableAutoConfiguration中的設置

extends WebMvcConfigurationAdapter/WebMvcConfigurer,在擴展的類中重寫父類的方法即可,這種方式依舊使用springboot的@EnableAutoConfiguration中的設置

WebMvcConfigurer 沒有暴露高級設置,如果需要高級設置 需要第二種方式繼承WebMvcConfigurationSupport或者DelegatingWebMvcConfiguration,例如:

@Configuration
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurationSupport {

@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(new MyConverter());
}

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// Create or delegate to "super" to create and
// customize properties of RequestMappingHandlerAdapter
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
所以無論是使用@EnableWebMvc還是WebMvcConfigurationSupport,都會禁止Spring Boot的自動裝配@EnableAutoConfiguration中的設置( 雖然禁止了Spring boot的自動裝配,但是WebMvcConfigurationSupport本身,還是會注冊一系列的MVC相關的bean的)。

@EnableAutoConfiguration是SpringBoot項目的啟動類注解@SpringBootApplication的子元素,@EnableAutoConfiguration實際是導入EnableAutoConfigurationImportSelector和Registar兩個類,主要功能是通過SpringFactoriesLoader.loadFactoryNames()導入jar下面配置文件META-INF/spring.factories。我們翻spring.factories,其中就包含WebMvc自動裝配類:

...
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
...
1
2
3
4
5
並且@EnableAutoConfiguration 注解,會自動讀取 application.properties 或 application.yml 文件中的配置。因此想想前面提到的第一個問題就很明白了。

如果想要使用自動配置生效,同時又要使用部分spring mvc默認配置的話,比如增加 viewController ,則可以將自己的配置類可以繼承 WebMvcConfigurerAdapter 這個類。不過在Spring5.0版本WebMvcConfigurerAdapter 后這個類被標記為@Deprecated了 。

* @author Rossen Stoyanchev
* @since 3.1
* @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 {
...
}
1
2
3
4
5
6
7
8
9
10
Spring 5.0后要使用Java8,而在Java8中接口是可以有default方法的,所以這個類就沒必要了。所以我們只需要在自定義配置類中直接實現 WebMvcConfigurer 接口就好了

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyWebConfig implements WebMvcConfigurer {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("helloworld");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
When we access URL /hello then helloworld.jsp will run.

對於第二個問題,如果使用@EnableWebMvc了,那么就會自動覆蓋了官方給出的/static, /public, META-INF/resources, /resources等存放靜態資源的目錄。而將靜態資源定位於src/main/webapp。當需要重新定義好資源所在目錄時,則需要主動添加上述的那個配置類,來重寫 addResourceHandlers方法。

@Configuration
@EnableWebMvc
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/public/");
}
}
1
2
3
4
5
6
7
8
9
從上述可知在SpringBoot中大多數時我們並不需要使用@EnableWebMvc注解,來看下官方的一段說明:

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.


https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration

說明:

Spring Boot 默認提供Spring MVC 自動配置,不需要使用@EnableWebMvc注解
如果需要配置MVC(攔截器、格式化、視圖等) 請使用添加@Configuration並實現WebMvcConfigurer接口.不要添加@EnableWebMvc注解。
@EnableWebMvc 只能添加到一個@Configuration配置類上,用於導入Spring Web MVC configuration
最后,如果Spring Boot在classpath里看到有 spring webmvc 也會自動添加@EnableWebMvc。
————————————————
版權聲明:本文為CSDN博主「zxc123e」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zxc123e/article/details/84636521


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM