1. 程式人生 > 其它 >Spring Boot學習-Spring MVC 自動配置原理

Spring Boot學習-Spring MVC 自動配置原理

技術標籤:Spring Boot學習spring bootjavaspring

Spring Boot為Spring MVC提供了自動配置,它可以很好地與大多數應用程式一起工作;

在Spring Boot的官方文件中已經對此有說明;

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

Spring MVC Auto-configuration
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

The auto-configuration adds the following features on top of Spring’s defaults:

Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

Support for serving static resources, including support for WebJars (covered later in this document)).

Automatic registration of Converter, GenericConverter, and Formatter beans.

Support for HttpMessageConverters (covered later in this document).

Automatic registration of MessageCodesResolver (covered later in this document).

Static index.html support.

Custom Favicon support (covered later in this document).

Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.

If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc, or alternatively add your own @Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.

在這一段說明中包含了很多與Spring MVC 自動配置有關的資訊;

Spring MVC 的預設配置檔案是WebMvcAutoConfiguration,我們已經知道當Spring Boot啟動專案時,會自動載入各種元件,而WebMvcAutoConfiguration就是其中一個;

我們找到WebMvcAutoConfiguration的原始碼,可以看到有這樣一段程式碼

		@Bean
        @ConditionalOnBean({ViewResolver.class})
        @ConditionalOnMissingBean(
            name =
{"viewResolver"}, value = {ContentNegotiatingViewResolver.class} ) public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) { ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); resolver.setContentNegotiationManager
((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class)); resolver.setOrder(-2147483648); return resolver; }

這個ContentNegotiatingViewResolver類就是一個內容協商檢視解析器,上面的文件也說了,自動配置會幫我們加入包含檢視解析器(ContentNegotiatingViewResolver and BeanNameViewResolver)在內的功能;

我們可以點進這個類ContentNegotiatingViewResolver,找到對應的解析檢視的程式碼

public View resolveViewName(String viewName, Locale locale) throws Exception {
        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
        List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
        if (requestedMediaTypes != null) {
            // 獲取候選的檢視物件
            List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
            // 選擇一個最適合的檢視物件,然後把這個物件返回
            View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
            if (bestView != null) {
                return bestView;
            }
        }

我們點進getCandidateViews這個方法中看看它是如何獲取候選檢視物件的

// 把所有的檢視解析器拿來,進行while迴圈,挨個解析
Iterator var5 = this.viewResolvers.iterator();

所以得出結論:ContentNegotiatingViewResolver 這個檢視解析器就是用來組合所有的檢視解析器的

我們再來看看它是從哪裡進行賦值的

protected void initServletContext(ServletContext servletContext) {
    // 從beanFactory工具中獲取容器中的所有檢視解析器
    Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
    ViewResolver viewResolver;
    if (this.viewResolvers == null) {
        this.viewResolvers = new ArrayList(matchingBeans.size());
    

那麼,我們就可以自己給容器中去新增一個檢視解析器,這個類就會幫我們自動的將它組合進來;

在主程式中自定義一個檢視解析器

@Bean //放到bean中
public ViewResolver myViewResolver(){
    return new MyViewResolver();
}

//我們寫一個靜態內部類,檢視解析器就需要實現ViewResolver介面
private static class MyViewResolver implements ViewResolver{
    @Override
    public View resolveViewName(String s, Locale locale) throws Exception {
        return null;
    }
}

然後我們可以通過在DispacherServlet中打斷點來除錯;

在這裡插入圖片描述

我們可以看到在viewResolvers中有我們自己匯入依賴後自動配置的TthmeleafViewResolver,也有我們自己新增在容器中的MyViewResolver;