本文介紹SpringBoot對Spring MVC自動配置,SpringBoot自動配置原理可以參考:【SpringBoot】SpringBoot配置與單元測試(二)
首先新建一個SpringBoot的web項目,參考:【SpringBoot】SpringBoot快速入門(一)
本例pom文件如下:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>com.test</groupId> 8 <artifactId>test-springboot-web</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 11 12 <parent> 13 <groupId>org.springframework.boot</groupId> 14 <artifactId>spring-boot-starter-parent</artifactId> 15 <version>2.1.8.RELEASE</version> 16 </parent> 17 18 <properties> 19 20 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 21 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 22 <java.version>1.8</java.version> 23 </properties> 24 25 <dependencies> 26 <dependency> 27 <groupId>org.springframework.boot</groupId> 28 <artifactId>spring-boot-starter-web</artifactId> 29 </dependency> 30 31 <!--引入jquery-webjar--> 32 <dependency> 33 <groupId>org.webjars</groupId> 34 <artifactId>jquery</artifactId> 35 <version>3.3.1</version> 36 </dependency> 37 38 <dependency> 39 <groupId>org.springframework.boot</groupId> 40 <artifactId>spring-boot-starter-test</artifactId> 41 <scope>test</scope> 42 </dependency> 43 44 </dependencies> 45 46 47 <!-- SpringBoot打包插件,可以將代碼打包成一個可執行的jar包 --> 48 <build> 49 <plugins> 50 <plugin> 51 <groupId>org.springframework.boot</groupId> 52 <artifactId>spring-boot-maven-plugin</artifactId> 53 </plugin> 54 </plugins> 55 </build> 56 </project>
SpringMVC自動配置
自動配置在Spring的默認值之上添加了以下功能:
- 包含
ContentNegotiatingViewResolver
和BeanNameViewResolver
。 - 支持服務靜態資源,包括對WebJars的支持。
- 自動注冊
Converter
,GenericConverter
和Formatter
豆類。 - 支持
HttpMessageConverters
。 - 自動注冊
MessageCodesResolver
。 - 靜態
index.html
支持。 - 定制
Favicon
支持。 - 自動使用
ConfigurableWebBindingInitializer
bean。
如果想保留Spring Boot MVC功能,並且想要添加其他MVC配置(攔截器,格式化程序,視圖控制器和其他功能),則可以編寫一個配置類(@Configuration),並
實現WebMvcConfigurer接口的類,但不能加 @EnableWebMvc
。如果您希望提供,或的自定義實例RequestMappingHandlerMapping
,則可以聲明一個實例來提供此類組件。RequestMappingHandlerAdapter、
ExceptionHandlerExceptionResolver、
WebMvcRegistrationsAdapter
如果想完全控制Spring MVC,可以在配置類(@Configuration)添加上
注釋@EnableWebMvc
。
添加MVC配置類
1、原理:
1)、WebMvcAutoConfiguration是SpringMVC的自動配置類
2)、在做其他自動配置時會導入;@Import(EnableWebMvcConfiguration.class)
3)、容器中所有的WebMvcConfigurer都會一起起作用;
4)、我們的配置類也會被調用;
2、編寫一個配置類(@Configuration),實現WebMvcConfigurer接口;不能標注@EnableWebMvc;
這樣既保留了所有的自動配置(WebMvcAutoConfiguration),也能用我們擴展的配置;
1 // @EnableWebMvc // 全面接管SpringMVC,所有的WebMvc自動配置都失效,如靜態資源的訪問都失效 2 @Configuration 3 public class MyMvcConfig implements WebMvcConfigurer { 4 5 @Override 6 public void addViewControllers(ViewControllerRegistry registry) { 7 // 瀏覽器訪問 "/success2" 重定向到 "/success" 8 registry.addRedirectViewController("/success2", "/success"); 9 // 瀏覽器訪問 "/success2" 轉發 "/success" 10 registry.addViewController("/success3").setViewName("/success"); 11 } 12 }
3、驗證:效果SpringMVC的自動配置和我們的擴展配置都會起作用
重定向請求驗證地址:http://localhost:8080/success
轉發請求驗證地址:http://localhost:8080/success
全面接管SpringMVC
1、原理
1)、查看源碼WebMvcAutoConfiguration類,有條件注解,在沒有WebMvcConfigurationSupport類的情況下才注入
@Configuration @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) // 條件判斷:在沒有WebMvcConfigurationSupport類的情況下才注入 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration {
2)、查看@EnableWebMvc注解源碼,發現它導入DelegatingWebMvcConfiguration類
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target(ElementType.TYPE) 3 @Documented 4 // 導入DelegatingWebMvcConfiguration類 5 @Import(DelegatingWebMvcConfiguration.class) 6 public @interface EnableWebMvc { 7 }
DelegatingWebMvcConfiguration類繼承了WebMvcConfigurationSupport類
1 @Configuration 2 public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3)、@EnableWebMvc將WebMvcConfigurationSupport組件導入進來,導入的WebMvcConfigurationSupport只是SpringMVC最基本的功能,WebMvcAutoConfiguration類又是在沒有WebMvcConfigurationSupport組件情況下生效,所以@EnableWebMvc能使WebMvcAutoConfiguration失效,並全面接管SpringMVC
靜態資源的映射規則
SpringBoot對靜態文件映射都在類中WebMvcAutoConfiguration,自動配置好了,打開WebMvcAutoConfiguration類,並分析
1、規則:/webjars/**
規則:所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找資源;
webjars:以jar包的方式引入靜態資源; 官網地址:http://www.webjars.org/
1 // 添加靜態資源映射 2 @Override 3 public void addResourceHandlers(ResourceHandlerRegistry registry) { 4 if (!this.resourceProperties.isAddMappings()) { 5 logger.debug("Default resource handling disabled"); 6 return; 7 } 8 Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); 9 CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); 10 if (!registry.hasMappingForPattern("/webjars/**")) { 11 // 添加映射 12 customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**") 13 .addResourceLocations("classpath:/META-INF/resources/webjars/") 14 .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); 15 } 16 String staticPathPattern = this.mvcProperties.getStaticPathPattern(); 17 if (!registry.hasMappingForPattern(staticPathPattern)) { 18 customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) 19 .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())) 20 .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); 21 } 22 }
測試:在pom文件中引入依賴
1 <!--引入jquery-webjar--> 2 <dependency> 3 <groupId>org.webjars</groupId> 4 <artifactId>jquery</artifactId> 5 <version>3.3.1</version> 6 </dependency>
可以看到jar包中有jquery.js文件
驗證:重啟項目,瀏覽器上打開地址:http://localhost:8080/webjars/jquery/3.3.1/jquery.js,即可看到能獲取到js文件
2、規則:/**
"/**" 訪問當前項目的任何資源,都去(靜態資源的文件夾)找映射,靜態資源的文件夾如下:
1 "classpath:/META-INF/resources/", 2 "classpath:/resources/", 3 "classpath:/static/", 4 "classpath:/public/"
測試:在類路徑中,創建static文件夾,在其中添加一個測試頁面test.html
驗證:重啟項目,瀏覽器使用地址:http://localhost:8080/test.html,訪問,即可看到test頁面
3、規則:首頁
首頁映射規則代碼在類中WebMvcAutoConfiguration,如下,也在靜態文件夾(即規則2下的文件夾)下查找
1 // 添加首頁映射 2 @Bean 3 public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext) { 4 WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping( 5 new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), 6 this.mvcProperties.getStaticPathPattern()); 7 welcomePageHandlerMapping.setInterceptors(getInterceptors()); 8 return welcomePageHandlerMapping; 9 }
測試:在類路徑中的static文件夾,在其中添加一個歡迎頁面index.html
驗證:重啟項目,瀏覽器使用地址:http://localhost:8080,訪問,即可看到歡迎頁面
4、規則:**/favicon.ico
所有的 **/favicon.ico 都是在靜態資源文件(即規則2下的文件夾)下找;
首頁映射規則代碼在類中WebMvcAutoConfiguration,如下
1 // 配置站點的圖標映射 2 @Configuration 3 @ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true) 4 public static class FaviconConfiguration implements ResourceLoaderAware { 5 6 private final ResourceProperties resourceProperties; 7 8 private ResourceLoader resourceLoader; 9 10 public FaviconConfiguration(ResourceProperties resourceProperties) { 11 this.resourceProperties = resourceProperties; 12 } 13 14 @Override 15 public void setResourceLoader(ResourceLoader resourceLoader) { 16 this.resourceLoader = resourceLoader; 17 } 18 19 @Bean 20 public SimpleUrlHandlerMapping faviconHandlerMapping() { 21 SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); 22 mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); 23 mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", faviconRequestHandler())); 24 return mapping; 25 } 26 27 @Bean 28 public ResourceHttpRequestHandler faviconRequestHandler() { 29 ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler(); 30 requestHandler.setLocations(resolveFaviconLocations()); 31 return requestHandler; 32 } 33 34 private List<Resource> resolveFaviconLocations() { 35 String[] staticLocations = getResourceLocations(this.resourceProperties.getStaticLocations()); 36 List<Resource> locations = new ArrayList<>(staticLocations.length + 1); 37 Arrays.stream(staticLocations).map(this.resourceLoader::getResource).forEach(locations::add); 38 locations.add(new ClassPathResource("/")); 39 return Collections.unmodifiableList(locations); 40 } 41 42 }
測試:在類路徑中的static文件夾,在其中添加一個favicon.ico圖標
驗證:重啟項目,瀏覽器使用地址:http://localhost:8080,訪問,即可看到瀏覽器標題上的站點圖標已改變