SpringBoot源碼學(xué)習(xí)系列之SpringMVC自動配置

源碼學(xué)習(xí)系列之WebMvc自動配置原理筆記

@[toc]

web的自動配置在SpringBoot項(xiàng)目中是一個很重要的方面,實(shí)現(xiàn)代碼在spring-boot-autoconfigure工程里:


在這里插入圖片描述

按照官方文檔的說法,SpringBoot官方的說法,Springboot的SpringMVC自動配置,主要提供了如下自動配置:


在這里插入圖片描述

WebMvcAutoConfiguration.java這個類很關(guān)鍵,這個就是SpringBoot Springmvc自動配置的一個很關(guān)鍵的配置類

@Configuration(proxyBeanMethods = false)//指定WebMvcAutoConfiguration不代理方法
@ConditionalOnWebApplication(type = Type.SERVLET)//在web環(huán)境(selvlet)才會起效
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })//系統(tǒng)有有Servlet,DispatcherServlet(Spring核心的分發(fā)器),WebMvcConfigurer的情況,這個自動配置類才起效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//系統(tǒng)沒有WebMvcConfigurationSupport這個類的情況,自動配置起效
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
        ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
....
}

翻下源碼,可以看到WebMvcAutoConfiguration自動配置類里還有一個WebMvcConfigurer類型的配置類,2.2.1版本是implements WebMvcConfigurer接口,1.+版本是extends WebMvcConfigurerAdapter


在這里插入圖片描述
@Configuration(proxyBeanMethods = false)//定義為配置類
    @Import(EnableWebMvcConfiguration.class)//spring底層注解,將EnableWebMvcConfiguration加到容器
    @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })//使WebMvcProperties、ResourceProperties配置類生效
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
    ....
}

1、ContentNegotiatingViewResolver

在這里插入圖片描述

如圖,是視圖解析器的自動配置,這個類起效的情況是系統(tǒng)沒有ContentNegotiatingViewResolver類的情況,就調(diào)用改方法自動創(chuàng)建ContentNegotiatingViewResolver類


在這里插入圖片描述

關(guān)鍵的是ContentNegotiatingViewResolver類,翻下ContentNegotiatingViewResolver類,找到如下重要的初始化方法

@Override
    protected void initServletContext(ServletContext servletContext) {
    //調(diào)用Spring的BeanFactoryUtils掃描容器里的所有視圖解析器ViewResolver類
        Collection<ViewResolver> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), ViewResolver.class).values();
        if (this.viewResolvers == null) {
            this.viewResolvers = new ArrayList<>(matchingBeans.size());
            //遍歷候選的viewResolvers,封裝到this.viewResolvers列表
            for (ViewResolver viewResolver : matchingBeans) {
                if (this != viewResolver) {
                    this.viewResolvers.add(viewResolver);
                }
            }
        }
        else {
            for (int i = 0; i < this.viewResolvers.size(); i++) {
                ViewResolver vr = this.viewResolvers.get(i);
                if (matchingBeans.contains(vr)) {
                    continue;
                }
                String name = vr.getClass().getName() + i;
                obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(vr, name);
            }

        }
        AnnotationAwareOrderComparator.sort(this.viewResolvers);
        this.cnmFactoryBean.setServletContext(servletContext);
    }

所以ContentNegotiatingViewResolver類的作用就是組合所有的視圖解析器,自動配置了ViewResolver(視圖解析器作用,根據(jù)方法返回值得到視圖對象view)

往下翻代碼,可以看到resolveViewName方法,里面代碼是從this.viewResolvers獲取候選的視圖解析器,遍歷容器里所有視圖,然后通過如圖所標(biāo)記的獲取候選視圖的方法,獲取候選的視圖列表,再通過getBestView獲取最合適的視圖


在這里插入圖片描述

遍歷所有的視圖解析器對象,從視圖解析器里獲取候選的視圖,封裝成list保存


在這里插入圖片描述

ok,跟了源碼就是只要將視圖解析器丟到Spring容器里,就可以加載到

寫個簡單的視圖解析類

在這里插入圖片描述

DispatcherServlet是Spring核心分發(fā)器,找到doDispatch方法,debug,可以看到加的視圖解析器加載到了
在這里插入圖片描述

2、靜態(tài)資源

也就是官方說的,如下圖所示:

在這里插入圖片描述

翻譯過來就是支持靜態(tài)資源包括webjars的自動配置,webjars,就是以maven等等方式打成jar包的靜態(tài)資源,可以去webjars官網(wǎng)看看文檔:

使用的話,直接去webjars官網(wǎng)負(fù)責(zé)對應(yīng)的配置,加到項(xiàng)目里就可以


在這里插入圖片描述

路徑都是在META-INF/webjars/**

WebMvcAutoConfiguration.addResourceHandlers,這個是比較重要的資源配置方法

@Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
                return;
            }
            Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
            //CacheControl是Spring框架提供的http緩存
            CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
            //讀取到webjars資源,將classpath:/META-INF/resources/webjars/的webjars資源都掃描出來
            if (!registry.hasMappingForPattern("/webjars/**")) {
                customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
                        .addResourceLocations("classpath:/META-INF/resources/webjars/")
                        .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
            }
            String staticPathPattern = this.mvcProperties.getStaticPathPattern();
            if (!registry.hasMappingForPattern(staticPathPattern)) {
                customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
                        .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
                        .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
            }
        }
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

ok,通過源碼可以知道,Springboot支持webjars和其它等等靜態(tài)資源,其它的靜態(tài)資源要放在如下目錄里,Springboot就能自動加載到

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/
  • classpath:/

3、自動注冊 Converter, GenericConverter, and Formatter beans.

在這里插入圖片描述

翻譯過來就是自動注冊了 Converter, GenericConverter, and Formatter beans.

  • Converter:轉(zhuǎn)換器 ,作用就是能自動進(jìn)行類型轉(zhuǎn)換
    eg: public String hello(User user),這是一個方法,然后前端視圖傳來的參數(shù)通過轉(zhuǎn)換器能夠根據(jù)屬性進(jìn)行映射,然后進(jìn)行屬性類型轉(zhuǎn)換
  • Formatter :格式化器,eg:比如對前端傳來的日期2019/11/25,進(jìn)行格式化處理

源碼在這里,WebMvcAutoConfiguration.addFormatters方法是添加格式化器的方法

在這里插入圖片描述

同理,也是從Spring容器里將這幾種類拿過來
在這里插入圖片描述

當(dāng)然,還有其它的,比如WebMvcAutoConfiguration.localeResolver方法是實(shí)現(xiàn)i18n國際化語言支持的自動配置

@Bean
        @ConditionalOnMissingBean//沒有自定義localeResolver的情況
        @ConditionalOnProperty(prefix = "spring.mvc", name = "locale")//application.properties有配置了spring.mvc.locale
        public LocaleResolver localeResolver() {
            if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.mvcProperties.getLocale());
            }
            //默認(rèn)使用AcceptHeaderLocaleResolver 
            AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
            localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
            return localeResolver;
        }

具體的源碼參考我之前博客:SpringBoot系列之i18n國際化多語言支持教程,博客里面有涉及源碼的

4、支持HttpMessageConverters

HttpMessageConverters :消息轉(zhuǎn)換器,Springmvc中用來轉(zhuǎn)換http請求和響應(yīng)的

源碼里是通過configureMessageConverters方法實(shí)現(xiàn),很顯然也是從容器里獲取的


在這里插入圖片描述
在這里插入圖片描述

官方文檔里也進(jìn)行了比較詳細(xì)描述,Springboot已經(jīng)為我們自動配置了json的、xml的自動轉(zhuǎn)換器,當(dāng)然你也可以自己添加


在這里插入圖片描述

5、支持MessageCodesResolver

在這里插入圖片描述

MessageCodesResolver:是消息解析器,WebMvcAutoConfiguration.getMessageCodesResolver是實(shí)現(xiàn)Exception異常信息格式的


在這里插入圖片描述

WebMvcProperties配置文件定義的一個異常枚舉值


在這里插入圖片描述
在這里插入圖片描述

格式為如圖所示,定了了錯誤代碼是生成規(guī)則:


在這里插入圖片描述

6、首頁支持

在這里插入圖片描述

Springboot默認(rèn)的首頁是index.html,也就是你在classpath路徑丟個index.html文件,就被Springboot默認(rèn)為首頁,或者說歡迎頁

如圖示代碼,就是遍歷靜態(tài)資源文件,然后獲取index.html作為歡迎頁面

在這里插入圖片描述

7、網(wǎng)站logo設(shè)置

在這里插入圖片描述

Springboot1.+版本,是有默認(rèn)的logo圖標(biāo)的,2.2.1版本,經(jīng)過全局搜索,沒有發(fā)現(xiàn)給自定義的圖標(biāo),使用的話,是直接丟在classpath路徑,文件命名為favicon.ico,不過在2.2.1代碼并沒有找到相應(yīng)的配置代碼,1.+版本是有的,不過文檔還是有描述了

8、ConfigurableWebBindingInitializer 初始綁定器

在這里插入圖片描述

跟下源碼,也是從Spring容器里獲取的,然后注意到,如果沒有這個ConfigurableWebBindingInitializer ,代碼就會調(diào)用基類的getConfigurableWebBindingInitializer


在這里插入圖片描述

源碼,這里也是創(chuàng)建一個getConfigurableWebBindingInitializer


在這里插入圖片描述

ConfigurableWebBindingInitializer 是Springboot為系統(tǒng)自動配置的,當(dāng)然我們也可以自己定義一個ConfigurableWebBindingInitializer ,然后加載到容器里即可

初始化綁定的方法,ok,本博客簡單跟一下源碼


在這里插入圖片描述

注意:
ok,Springboot官方文檔里還有這樣的描述,如圖所示

在這里插入圖片描述

意思是,在使用webmvcConfigurer配置的時候,不要使用@EnableWebMvc注解,為什么不要使用呢?因?yàn)槭褂昧薂EnableWebMvc,就是實(shí)現(xiàn)全面接管SpringMVC自動配置,也就是說其它的自動配置都會失效,全部自己配置

原理是為什么?可以簡單跟一下源碼,如圖,SpringMVC自動配置類,有這個很關(guān)鍵的注解,這個注解的意思是@WebMvcConfigurationSupport注解不在系統(tǒng)時候自動配置才起效

在這里插入圖片描述

然后為什么加了@EnableWebMvc自動配置就可以被全面接管?點(diǎn)一下@EnableWebMvc源碼

在這里插入圖片描述

很顯然,DelegatingWebMvcConfiguration類extends WebMvcConfigurationSupport類,所以這也就是為什么@EnableWebMvc注解能實(shí)現(xiàn)全面接管自動配置的原理
在這里插入圖片描述
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容