【Spring Boot】(13)、Spring Boot自動配置SpringMVC
1、SpringMVC自動配置官方文件
2、Spring MVC auto-configuration
以下是Spring Boot對SpringMVC的預設配置(來自官網,自行翻譯):
自動配置了
ContentNegotiatingViewResolver
和BeanNameViewResolver
的Beans.給容器自定義新增一個檢視解析器,該ContentNegotiatingViewResolver 的bean會自動組合進來。
自動配置了ViewResolver:ContentNegotiatingViewResolver
public class WebMvcAutoConfiguration { //other code... @Bean @ConditionalOnBean(ViewResolver.class) @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class) public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) { ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); resolver.setContentNegotiationManager( beanFactory.getBean(ContentNegotiationManager.class)); // ContentNegotiatingViewResolver uses all the other view resolvers to locate // a view so it should have a high precedence resolver.setOrder(Ordered.HIGHEST_PRECEDENCE); return resolver; } }
其中ContentNegotiatintViewResolver類實現ViewResoler介面:
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean { //other code... @Override public View resolveViewName(String viewName, Locale locale) throws Exception { RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes"); //獲取所有的MediaType,例如application/json,text/html等等。。。 List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest()); if (requestedMediaTypes != null) { //獲取所有的檢視 List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes); //根據請求獲取最適合的檢視 View bestView = getBestView(candidateViews, requestedMediaTypes, attrs); if (bestView != null) { return bestView; } } //other code... } private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception { List<View> candidateViews = new ArrayList<View>(); for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { candidateViews.add(view); } for (MediaType requestedMediaType : requestedMediaTypes) { List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType); for (String extension : extensions) { String viewNameWithExtension = viewName + '.' + extension; view = viewResolver.resolveViewName(viewNameWithExtension, locale); if (view != null) { candidateViews.add(view); } } } } //other code... return candidateViews; } }
支援靜態資原始檔夾和webjars
靜態首頁的訪問。
自定義favicon圖示
自動註冊了
Converter
,GenericConverter
,Formatter
Beans.Converter:轉換器,用於型別轉換
Formatter:格式化器
@Bean
//如果配置了spring.mvc.date-format,則自動註冊Formatter<Date>的Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat());
}
自動新增的格式化轉換器,只需新增到容器中即可。
支援
HttpMessageConverters
訊息轉換器。HttpMessageConverter:SpringMVC用來轉換Http請求和響應的
HttpMessageConverters
是從容器中獲取的所有的HttpMessageConverter,如果需要給容器中新增HttpMessageConverter,只需要將自定義的元件註冊在容器中即可。
自動配置
MessageCodesResolver
用於錯誤程式碼的生成規則。PREFIX_ERROR_CODE: error_code + "." + object name + "." + field
POSTFIX_ERROR_CODE:object name + "." + field + "." + error_code
自動使用
ConfigurableWebBindingInitializer
Bean。可以自定義配置一個
ConfigurableWebBindingInitializer
來替換預設的,需要新增到容器中。初始化WebDataBinder:用於將請求資料繫結到資料模型等。
包org.springframework.boot.autoconfigure.web是web的所有自動配置場景。
(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
.
3、擴充套件SpringMVC
編寫一個配置類,是WebMvcConfigurerAdapter類的子類,但是不能標註@EnableWebMvc註解。
這樣既保留了所有的自動配置,也能使用自定義的擴充套件配置。
//使用WebMvcConfigurerAdapter可以來擴充套件SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//瀏覽器傳送/cay請求,會直接跳到success頁面。
registry.addViewController("/cay").setViewName("success");
}
}
1)、WebMvcAutoConfiguration是SpringMVC的自動配置類,在內部維護了一個內部類WebMvcAutoConfigurationAdapter,該類又繼承自WebMvcConfigurerAdapter,看定義:
@Configuration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {}
而WebMvcConfigurerAdapter又實現了WebMvcConfigurer介面:
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {}
所以自定義的配置類(此例為MyMvcConfig)是個WebMvcConfigurer介面的實現類。WebMvcAutoConfigurationAdapter自動配置時會匯入
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {}
父類:
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
//從容器中獲取所有的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
}
3)、容器中所有的WebMvcConfigurer都會一起起作用。
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<WebMvcConfigurer>();
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
@Override
public void addFormatters(FormatterRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addFormatters(registry);
}
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addInterceptors(registry);
}
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
}
//other code...
}
從原始碼中可以看到,從容器中獲取的所有WebMvcConfigurer物件都會被呼叫對應的配置方法。
4)、最後可以結合第2點和第3點看出,自定義的配置類也會被呼叫。
總結:SpringMVC的自動配置和自定義的擴充套件配置都會起作用。
4、全面接管SpringMVC
@EnableWebMvc註解,這樣Spring Boot對SpringMVC的自動配置就失效了,所有都需要自定義配置。
原理:為什麼使用了@EnableWebMvc後自動配置就失效了?
1)、EnableWebMvc註解的定義
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {}
2)、匯入了DelegatingWebMvcConfiguration元件配置
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}
3)、檢視WebMvcAutoConfiguration自動配置類的簽名
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
//如果容器中沒有該元件的時候,這個自動配置類就自動生效。
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {}
4)、@EnableWebMvc將WebMvcConfigurationSupport元件匯入進來了,導致Spring Boot對SpringMVC的自動配置失效,即WebMvcAutoonfiguration配置類未註冊成功。
5、修改SpringBoot的預設配置
1)、Spring Boot在自動配置很多元件的時候,會先檢查容器中是否有使用者自定義配置的Bean或者元件。如果有,就使用使用者自定義的;如果沒有,Spring Boot才自動配置;如果有些元件可以有多個,使用者可以自定義新增元件,並加入到容器中,這樣Spring Boot會自動將使用者配置的和預設的組合起來。
2)、在Spring Boot中會有很多的Configurer幫助使用者進行擴充套件配置。
====================打個廣告,歡迎關注====================