SpringBoot——web開發之SpringMVC自動配置原理
一、SpringBoot為SpringMVC提供的自動配置
2、SpringBoot為SpringMVC提供的自動配置:參考類WebMvcAutoConfiguration
①Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans
SpringBoot為SpringMVC自動配置了ViewResolver(檢視解析器:根據方法的返回值得到檢視物件——View,檢視物件決定如何渲染,是轉發還是重定向),SpringBoot通過ContentNegotiatingViewResolver組合所有的檢視解析器(遍歷容器中所有的檢視解析器,並將這些檢視解析器新增到viewResolvers中):
protected void initServletContext(ServletContext servletContext) { Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values(); ViewResolver viewResolver; if (this.viewResolvers == null) { this.viewResolvers = new ArrayList(matchingBeans.size()); Iterator var3 = matchingBeans.iterator(); while(var3.hasNext()) { viewResolver = (ViewResolver)var3.next(); if (this != viewResolver) { this.viewResolvers.add(viewResolver); } } } else { for(int i = 0; i < this.viewResolvers.size(); ++i) { viewResolver = (ViewResolver)this.viewResolvers.get(i); if (!matchingBeans.contains(viewResolver)) { String name = viewResolver.getClass().getName() + i; this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name); } } } if (this.viewResolvers.isEmpty()) { this.logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the 'viewResolvers' property on the ContentNegotiatingViewResolver"); } AnnotationAwareOrderComparator.sort(this.viewResolvers); this.cnmFactoryBean.setServletContext(servletContext); }
我們可以自己定製檢視解析器,並將自定義的檢視解析器新增到容器中:ContentNegotiatingViewResolver會自動的將其組合進來,例如:這裡定義了一個靜態內部類,使其實現ViewResolver介面
@SpringBootApplication public class SpringBootWebApplication { public static void main(String[] args) { SpringApplication.run(SpringBootWebApplication.class, args); } @Bean public ViewResolver myViewResolver(){ return new MyViewResolver(); } public static class MyViewResolver implements ViewResolver{ @Override public View resolveViewName(String s, Locale locale) throws Exception { return null; } } }
②Support for serving static resources, including support for WebJars (see below):SpringBoot支援靜態資原始檔夾路徑,包括webjars
③Static index.html support:SpringBoot提供了靜態首頁訪問
④Custom Favicon support (see below):自定義的 favicon.ico
⑤自動註冊了Converter , GenericConverter , Formatter beans等轉換器(轉換器:頁面傳給後臺的值都是文字型別的,後臺拿到這些資料封裝物件的時候可能需要進行型別轉換,比如將"true"轉換為Boolean型別,將“18”轉為Integer型別等)和格式化器
@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date‐format")//在檔案中配置日期格式化的規則
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化元件
}
我們也可以自定義格式化器,方式類似於自定義檢視解析器
⑥Support for HttpMessageConverters (see below):HTTP訊息轉換器,比如報文是物件還是JSON格式,也可以自定義
⑦Automatic registration of MessageCodesResolver (see below):定義錯誤程式碼生成規則
⑧Automatic use of a ConfigurableWebBindingInitializer bean (see below):自動將請求資料轉化為JavaBean,可自定義
SpringBoot為SpringMVC做的所有自動配置都在org.springframework.boot.autoconfigure.web下
另外:
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration(interceptors, formatters, view controllers etc.)you can add your own @Configuration class of type WebMvcConfigurerAdapter,but without @EnableWebMvc . If you wish to provide custom instances of RequestMappingHandlerMapping , RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.
二、如何修改SpringBoot的預設配置
模式:
1、SpringBoot在自動配置很多元件的時候,會先看容器中有沒有使用者自己配置的(@Bean、@Component)對應元件,如 果有就用使用者配置的,如果沒有,才自動配置;如果有些元件可以有多個(比如ViewResolver)SpringBoot會將使用者配置的和默 認的組合起來:通過註解@ConditionalOnMissingBean來判斷使用者有沒有自定義元件
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
2、在SpringBoot中會有非常多的XxxConfigurer幫助我們進行擴充套件配置
3、在SpringBoot中會有很多的XxxCustomizer幫助我們進行定製配置
三、擴充套件SpringMVC
比如:配置某些請求的檢視或者某些請求的攔截器,在之前我們可以這麼配置
<mvc:view-controller path="/hello" view-name="success"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean></bean>
</mvc:interceptor>
</mvc:interceptors>
現在我們可以自定義一個配置類:使用@Configuration標註,是WebMvcConfigurerAdapter型別,不能標註@EnableWebMvc,然後重寫相應的方法即可,這樣我們既保留了SpringBoot中所有的自動配置,也啟用了我們擴充套件的配置
//通過重寫WebMvcConfigurerAdapter的相應方法來擴充套件SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//對於一些簡單的請求,比如不需要從後臺獲取資料的請求,可以採用這種方式直接返回頁面,而不需要在Controller中寫一些空方法
registry.addViewController("/bdm").setViewName("success");
}
}
擴充套件原理:
在做其他自動配置時會匯入EnableWebMvcConfiguration:@Import(EnableWebMvcConfiguration.class)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
...
}
在該類中會將所有的WebMvcConfigurer組合起來:使容器中所有的WebMvcConfigurer一起起作用
//從容器中獲取所有的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
//一個參考實現;將所有的WebMvcConfigurer相關配置都來一起呼叫;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
...
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
...
}
四、全盤接管SpringgMVC
當我們不需要使用SpringBoot為SpringMVC提供的所有自動配置的時候,可以全面接管SpringMVC(不推薦這樣做),只需要在配置類中新增@EnableWebMvc即可:
//通過重寫WebMvcConfigurerAdapter的相應方法來擴充套件SpringMVC
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//對於一些簡單的請求,比如不需要從後臺獲取資料的請求,可以採用這種方式直接返回頁面,而不需要在Controller中寫一些空方法
registry.addViewController("/bdm").setViewName("success");
}
}
原理:
SpringBoot中為SpringMVC提供的自動配置生效的前提是容器中不存在WebMvcConfigurationSupport:
@Configuration @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})@ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) @AutoConfigureOrder(-2147483638) @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class}) public class WebMvcAutoConfiguration { ... }
一旦容器中存在了WebMvcConfigurationSupport,則WebMvcAutoConfiguration元件不會被載入到容器中,而@EnableWebMvc會@Import({DelegatingWebMvcConfiguration.class}),DelegatingWebMvcConfiguration繼承自WebMvcConfigurationSupport,因此會導致WebMvcAutoConfiguration失效
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
}
WebMvcConfigurationSupport中只實現了SpringMVC最基本的功能,所以不推薦全面接管SpringMVC,除非專案中很少使用web模組