源码学习系列之WebMvc自动配置原理笔记

@

web的自动配置在SpringBoot项目中是一个很重要的方面,实现代码在spring-boot-autoconfigure工程里:



按照官方文档的说法,SpringBoot官方的说法,Springboot的SpringMVC自动配置,主要提供了如下自动配置:

WebMvcAutoConfiguration.java这个类很关键,这个就是SpringBoot Springmvc自动配置的一个很关键的配置类

@Configuration(proxyBeanMethods = false)//指定WebMvcAutoConfiguration不代理方法
@ConditionalOnWebApplication(type = Type.SERVLET)//在web环境(selvlet)才会起效
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })//系统有有Servlet,DispatcherServlet(Spring核心的分发器),WebMvcConfigurer的情况,这个自动配置类才起效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//系统没有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



如图,是视图解析器的自动配置,这个类起效的情况是系统没有ContentNegotiatingViewResolver类的情况,就调用改方法自动创建ContentNegotiatingViewResolver类



关键的是ContentNegotiatingViewResolver类,翻下ContentNegotiatingViewResolver类,找到如下重要的初始化方法

@Override
protected void initServletContext(ServletContext servletContext) {
//调用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(视图解析器作用,根据方法返回值得到视图对象view)

往下翻代码,可以看到resolveViewName方法,里面代码是从this.viewResolvers获取候选的视图解析器,遍历容器里所有视图,然后通过如图所标记的获取候选视图的方法,获取候选的视图列表,再通过getBestView获取最合适的视图



遍历所有的视图解析器对象,从视图解析器里获取候选的视图,封装成list保存



ok,跟了源码就是只要将视图解析器丢到Spring容器里,就可以加载到

写个简单的视图解析类



DispatcherServlet是Spring核心分发器,找到doDispatch方法,debug,可以看到加的视图解析器加载到了

2、静态资源

也就是官方说的,如下图所示:



翻译过来就是支持静态资源包括webjars的自动配置,webjars,就是以maven等等方式打成jar包的静态资源,可以去webjars官网看看文档:

使用的话,直接去webjars官网负责对应的配置,加到项目里就可以



路径都是在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和其它等等静态资源,其它的静态资源要放在如下目录里,Springboot就能自动加载到

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

3、自动注册 Converter, GenericConverter, and Formatter beans.



翻译过来就是自动注册了 Converter, GenericConverter, and Formatter beans.

  • Converter:转换器 ,作用就是能自动进行类型转换

    eg: public String hello(User user),这是一个方法,然后前端视图传来的参数通过转换器能够根据属性进行映射,然后进行属性类型转换
  • Formatter :格式化器,eg:比如对前端传来的日期2019/11/25,进行格式化处理

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



同理,也是从Spring容器里将这几种类拿过来

当然,还有其它的,比如WebMvcAutoConfiguration.localeResolver方法是实现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());
}
//默认使用AcceptHeaderLocaleResolver
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}

具体的源码参考我之前博客:SpringBoot系列之i18n国际化多语言支持教程,博客里面有涉及源码的

4、支持HttpMessageConverters

HttpMessageConverters :消息转换器,Springmvc中用来转换http请求和响应的

源码里是通过configureMessageConverters方法实现,很显然也是从容器里获取的



官方文档里也进行了比较详细描述,Springboot已经为我们自动配置了json的、xml的自动转换器,当然你也可以自己添加

5、支持MessageCodesResolver



MessageCodesResolver:是消息解析器,WebMvcAutoConfiguration.getMessageCodesResolver是实现Exception异常信息格式的



WebMvcProperties配置文件定义的一个异常枚举值



格式为如图所示,定了了错误代码是生成规则:

6、首页支持



Springboot默认的首页是index.html,也就是你在classpath路径丢个index.html文件,就被Springboot默认为首页,或者说欢迎页

如图示代码,就是遍历静态资源文件,然后获取index.html作为欢迎页面

7、网站logo设置



Springboot1.+版本,是有默认的logo图标的,2.2.1版本,经过全局搜索,没有发现给自定义的图标,使用的话,是直接丢在classpath路径,文件命名为favicon.ico,不过在2.2.1代码并没有找到相应的配置代码,1.+版本是有的,不过文档还是有描述了

8、ConfigurableWebBindingInitializer 初始绑定器



跟下源码,也是从Spring容器里获取的,然后注意到,如果没有这个ConfigurableWebBindingInitializer ,代码就会调用基类的getConfigurableWebBindingInitializer



源码,这里也是创建一个getConfigurableWebBindingInitializer

ConfigurableWebBindingInitializer 是Springboot为系统自动配置的,当然我们也可以自己定义一个ConfigurableWebBindingInitializer ,然后加载到容器里即可

初始化绑定的方法,ok,本博客简单跟一下源码

注意:

ok,Springboot官方文档里还有这样的描述,如图所示



意思是,在使用webmvcConfigurer配置的时候,不要使用@EnableWebMvc注解,为什么不要使用呢?因为使用了@EnableWebMvc,就是实现全面接管SpringMVC自动配置,也就是说其它的自动配置都会失效,全部自己配置

原理是为什么?可以简单跟一下源码,如图,SpringMVC自动配置类,有这个很关键的注解,这个注解的意思是@WebMvcConfigurationSupport注解不在系统时候自动配置才起效



然后为什么加了@EnableWebMvc自动配置就可以被全面接管?点一下@EnableWebMvc源码



很显然,DelegatingWebMvcConfiguration类extends WebMvcConfigurationSupport类,所以这也就是为什么@EnableWebMvc注解能实现全面接管自动配置的原理

SpringBoot源码学习系列之SpringMVC自动配置的更多相关文章

  1. SpringBoot源码学习系列之异常处理自动配置

    SpringBoot源码学习系列之异常处理自动配置 1.源码学习 先给个SpringBoot中的异常例子,假如访问一个错误链接,让其返回404页面 在浏览器访问: 而在其它的客户端软件,比如postm ...

  2. SpringBoot源码学习系列之Locale自动配置

    目录 1.spring.messages.cache-duration 2.LocaleResolver 的方法名必须为localeResolver 3.默认LocaleResolver 4.指定默认 ...

  3. SpringBoot源码学习系列之嵌入式Servlet容器

    目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...

  4. SpringBoot源码学习系列之@PropertySource不支持yaml读取原因

    然后,为什么@PropertySource注解默认不支持?可以简单跟一下源码 @PropertySource源码: 根据注释,默认使用DefaultPropertySourceFactory类作为资源 ...

  5. SpringBoot源码学习系列之启动原理简介

    本博客通过debug方式简单跟一下Springboot application启动的源码,Springboot的启动源码是比较复杂的,本博客只是简单梳理一下源码,浅析其原理 为了方便跟源码,先找个Ap ...

  6. 源码学习系列之SpringBoot自动配置(篇二)

    源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析 继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续 ...

  7. 源码学习系列之SpringBoot自动配置(篇一)

    源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...

  8. SpringBoot源码解析系列文章汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的SpringBoot源码解析系列文章的汇总,当你使用SpringBoot不仅仅满足于基本使用时.或者出去面试被面试官虐了时.或者说想要深入了解一下 ...

  9. Java并发包源码学习系列:阻塞队列BlockingQueue及实现原理分析

    目录 本篇要点 什么是阻塞队列 阻塞队列提供的方法 阻塞队列的七种实现 TransferQueue和BlockingQueue的区别 1.ArrayBlockingQueue 2.LinkedBloc ...

随机推荐

  1. Yii2.0教程应用结构篇 —— 入口脚本

    入口脚本是应用启动流程中的第一环,一个应用(不管是网页应用还是控制台应用)只有一个入口脚本.终端用户的请求通过入口脚本实例化应用并将将请求转发到应用. Web 应用的入口脚本必须放在终端用户能够访问的 ...

  2. 使用 pdf.js 在网页中加载 pdf 文件

    在网页中加载并显示PDF文件是最常见的业务需求.例如以下应用场景:(1)在电商网站上购物之后,下载电子发票之前先预览发票.(2)电子商务管理系统中查看发布的公文,公文文件一般是PDF格式的文件. 目前 ...

  3. 【译】Source Maps浅析

    Time:2019/10/27~2019/10/29 Link: 原文链接 译文开始: 对网站进行性能优化对一个最容易的方法就是把JS和CSS进行打包压缩.但是当你需要调试这些压缩文件中的代码的时候, ...

  4. ASP.NET Core 3.0 : 二十八. 在Docker中的部署以及docker-compose的使用

    本文简要说一下ASP.NET Core 在Docker中部署以及docker-compose的使用  (ASP.NET Core 系列目录). 系统环境为CentOS 8 . 打个广告,求职中.. 一 ...

  5. ARM、X86和AI处理器的区别

    ARM.X86和AI处理器的区别 目前主要的处理器架构有: X86: Intel, AMD, 海光, 兆芯 ARM: 华为,飞腾,华芯通,Cavium,Ampere,富士通,亚马逊 POWER:IBM ...

  6. element 自定义 el-loading

    前言 虽说,el-loading 自带的loading效果已经满足日常的需求看 但是,美术大大觉得太low  我要我设计的,我不要你觉得我要我觉得 需求 自定义el-loading 正文 从官方需求文 ...

  7. 第六篇 视觉slam中的优化问题梳理及雅克比推导

    优化问题定义以及求解 通用定义 解决问题的开始一定是定义清楚问题.这里引用g2o的定义. \[ \begin{aligned} \mathbf{F}(\mathbf{x})&=\sum_{k\ ...

  8. 深度学习tensorflow实战笔记(1)全连接神经网络(FCN)训练自己的数据(从txt文件中读取)

    1.准备数据 把数据放进txt文件中(数据量大的话,就写一段程序自己把数据自动的写入txt文件中,任何语言都能实现),数据之间用逗号隔开,最后一列标注数据的标签(用于分类),比如0,1.每一行表示一个 ...

  9. NOIP模拟 18

    这次时间分配不合理,沉迷大模拟无法自拔 虽然A了但是根本就没给T3留时间555 T3如果有时间看看数据范围应该可以想到QJ掉20分的555 T1 引子 打这题的时候感觉自己在做图像处理.. 然后调了各 ...

  10. 利用Nginx中的Upstream模块配置服务器负载均衡

    1. 前言 nginx有一个最大的功能就是可以实现服务器的负载均衡,本篇博文就利用nginx中的upstream模块来配置一个简单的负载均衡.关于nginx的安装和配置文件可以查阅博文:windows ...