目录
1,ContentNegotiatingViewResolver
2, 静态资源
3, 自动注册 Converter, GenericConverter, and Formatter beans.
4, 支持 HttpMessageConverters
5, 支持 MessageCodesResolver
6, 首页支持
7, 网站 logo 设置
8,ConfigurablewebBindingInitializer 初始绑定器
源码学习系列之 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 {
- ....
- }
ok, 跟一下 WebMvcAutoConfigurationAdapter 里的关键重载方法:
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 官网 https://www.webjars.org/ 看看文档:
使用的话, 直接去 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 注解能实现全面接管自动配置的原理
来源: https://www.cnblogs.com/mzq123/p/11936054.html