Springboot MVC 自动配置

官方文档阅读

https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.servlet.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.
  • 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.

如果您希望保留 Spring Boot MVC 定制并进行更多的 MVC 定制(拦截器、格式化程序、视图控制器和其他特性) ,可以添加您自己的 webmvcrer 类型的@Configuration 类,但不要添加@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.

如果你想提供自定义的 requestmappinghandler mapping、 requestmappinghandler adapter 或 exceptionhandlerexceptionmvc 定制,你可以声明一个类型为 WebMvcRegistrations 的 bean,并使用它来提供这些组件的自定义实例

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,你可以添加你自己的@Configuration 注释@EnableWebMvc,或者像在@EnableWebMvc 的 Javadoc 中描述的那样添加你自己的@Configuration 注释 delegatingwebmvcvc 配置。

个人解读

​ SpringBoot本身是为Spring MVC提供了自动配置,一般情况下是满足使用需求的。最近在学习的时候,需要使用矩阵变量,需要对springmvc的配置需要进行更改,遇到了一些疑问,通过源码探索了一下,今天在此总结,方便以后自己来看。

​ 上面的官方文档中,最重要的两段话:

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.(在自动配置的基础上,进行用户自定义配置)

如果您希望保留 Spring Boot MVC 定制并进行更多的 MVC 定制(拦截器、格式化程序、视图控制器和其他特性) ,可以添加您自己的 WebMvcConfigurer类型的@Configuration 类但不要添加@EnableWebMvc

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,你可以添加你自己的@Configuration 注释@EnableWebMvc,或者添加自己的@Configuration-annotated DelegatingWebMvcConfiguration中的Javadoc中所述@EnableWebMvc

总结一下:如果我们需要定制适合当前开发需求的springmvc,那么有两种方法:

  • (推荐)在使用@Configuration注解的配置类中,实现WebMvcConfigurer接口并重写对应方法或者添加一个用户自定义的WebMvcConfigurer组件,但不能使用@EnableWebMvc
  • 使用@Configuration注解的同时,使用@EnableWebMvc

深入理解

首先我们得知道:(推荐使用在自动配置的基础上进行更多定制,即同时使用自动配置以及用户自定义配置

SpringBoot会默认自动配置组件,在自动配置组件的时候,首先会查看IOC容器中是否有用户自定义配置的(即,在@Configuration配置类中,用户使用@Bean添加进容器中的组件),如果有就用用户配置的,如果没有就用自动配置的;如果有些组件可以存在多个,比如我们的视图解析器,就将用户配置的和自己默认的组合起来。

示例代码

这里是推荐方法的使用,至于全面接管的使用,后面再更新吧(如果你看到了这句话,那还没有更新.........)

  • 第一种,实现WebMvcConfigurer接口并重写对应方法
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 移除url中分号:设置为false,不移除;这样,才能从url中取出矩阵变量的值
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
  • 第二种:在配置类中,用户使用WebMvcConfigurer定制化SpringMVC的功能,并添加到容器中
@Configuration
public class WebConfig /*implements WebMvcConfigurer*/ { // WebMvcConfigurer定制化SpringMVC的功能
@Bean
public WebMvcConfigurer webMvcConfigurer(){
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 不移除;后面的内容。矩阵变量功能就可以生效
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}

自动配置原理(推荐方法)

WebMvcConfigurer

  1. 我们知道springboot是自动配置类是WebMvcAutoConfiguration.class

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
    @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
    ValidationAutoConfiguration.class })
    public class WebMvcAutoConfiguration {
    ......
    }
  2. WebMvcAutoConfiguration.class中有一个静态类WebMvcAutoConfigurationAdapter实现了WebMvcConfigurer

    	@Configuration(proxyBeanMethods = false)
    @Import(EnableWebMvcConfiguration.class)
    @EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {...}
  3. WebMvcAutoConfigurationAdapter类是实现了WebMvcConfigurer接口,WebMvcConfigurer中提供了许多默认实现的方法,我们正是通过对这些方法的重写,来达到定制的目的。

    public interface WebMvcConfigurer {
    
    	default void configurePathMatch(PathMatchConfigurer configurer) {
    }
    .......
    }
  4. 从注解@Import(EnableWebMvcConfiguration.class)看到,WebMvcAutoConfiguration导入了一个配置等效于@EnableWebMvc的配置类,这个类继承了DelegatingWebMvcConfiguration,而DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport

    DelegatingWebMvcConfiguration这个类的作用:其实是调用WebMvcConfigurerComposite这个类中的方法,目的是同时加载自动配置和用户自定义的配置

    /**
    * A subclass of {@code WebMvcConfigurationSupport} that detects and delegates
    * to all beans of type {@link WebMvcConfigurer} allowing them to customize the
    * configuration provided by {@code WebMvcConfigurationSupport}. This is the
    * class actually imported by {@link EnableWebMvc @EnableWebMvc}.
    *
    * @author Rossen Stoyanchev
    * @since 3.1
    *WebMvcConfigurationSupport的子类,它检测并委托给WebMvcConfigurer类型的所有bean,允许它们自定义WebMvcConfigurationSupport提供的配置。 这是由@EnableWebMvc实际导入的@EnableWebMvc
    */
    @Configuration(proxyBeanMethods = false)
    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
    if (!CollectionUtils.isEmpty(configurers)) {
    this.configurers.addWebMvcConfigurers(configurers);
    }
    } ........
    }

    我们随机选择这个类中任意一个方法,并进入到调用的对应WebMvcConfigurerComposite类中的方法,可以发现:

    这个类的方法,将实现所有WebMvcConfigurer的相关配置bean,包括我们自己配置的和SpringBoot给我们自动配置的,即这里完成了在自动配置的基础上增加我们自定义的配置。下面给出两个示例方法:

    	@Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
    if (!CollectionUtils.isEmpty(configurers)) {
    // 从容器中获取所有自定义配置bean
    this.configurers.addWebMvcConfigurers(configurers);
    }
    } @Override
    protected void configurePathMatch(PathMatchConfigurer configurer) {
    // 遍历容器中中相关配置并调用
    this.configurers.configurePathMatch(configurer);
    }

    查看configurePathMatch()方法:

    将各种自定义配置bean(即WebMvcConfigurer对象)添加到delegates中,并将所有的WebMvcConfigurer相关配置使用对应的方法进行遍历调用(包括springboot自动配置的和我们用户自定义配置的)。

    class WebMvcConfigurerComposite implements WebMvcConfigurer {
    
    	private final List<WebMvcConfigurer> delegates = new ArrayList<>();
    
    	public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
    if (!CollectionUtils.isEmpty(configurers)) {
    this.delegates.addAll(configurers);
    }
    } @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
    // 遍历调用实现,实现默认的配置以及自定义的配置
    for (WebMvcConfigurer delegate : this.delegates) {
    delegate.configurePathMatch(configurer);
    }
    }
    ....
    }

总结1

所有的WebMvcConfiguration都会被调用,包括springboot自动配置的内容以及我们自己定义的配置。

为什么不能使用@EnableWebMvc(完全控制Spring MVC)

完全控制Spring MVC:SpringBoot对SpringMVC的自动配置失效,所有配置都需要用户自己去配置。

前面提到,如果使用第一种方法的话,就不能使用@EnableWebMvc注解,从WebMvcConfigurer的实现类WebMvcAutoConfigurationAdapter所在的springboot自动配置类WebMvcAutoConfiguration可以看到:

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

只有当容器里面没有WebMvcConfigurationSupport这个组件时,才能使用SpringBoot的自动配置。所以,当我们使用第一种自动配置+自定义配置时,不能使用@EnableWebMvc注解的原因就在此。(从自动配置类WebMvcAutoConfiguration直观分析)

进一步理解,加入@EnableWebMvc注解后SpringMVC的所有自动配置失效的原理:

  1. 查看@EnableWebMvc注解的定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
  1. 这个要导入DelegatingWebMvcConfiguration组件:
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {...}

可以看到DelegatingWebMvcConfiguration是继承WebMvcConfigurationSupport,也就是说如果使用注解@EnableWebMvc,就会向容器添加组件DelegatingWebMvcConfiguration,等同于导入了WebMvcConfigurationSupport,这与springboot自动配置类使用的条件冲突,导致自动配置失效。

总结2

@EnableWebMvc将WebMvcConfigurationSupport组件导入进容器中来了,会导致自动配置失效。

Springboot MVC 自动配置的更多相关文章

  1. springboot mvc自动配置(三)初始化mvc的组件

    所有文章 https://www.cnblogs.com/lay2017/p/11775787.html 正文 在springboot mvc自动配置的时候,获得了DispatcherServlet和 ...

  2. springboot mvc自动配置(目录)

    对于长时间基于spring框架做web开发的我们,springmvc几乎成为了开发普通web项目的标配.本系列文章基于快速启动的springboot,将从源码角度一点点了解springboot中mvc ...

  3. springboot mvc自动配置(一)自动配置DispatcherServlet和DispatcherServletRegistry

    所有文章 https://www.cnblogs.com/lay2017/p/11775787.html 正文 springboot的自动配置基于SPI机制,实现自动配置的核心要点就是添加一个自动配置 ...

  4. 全网最深分析SpringBoot MVC自动配置失效的原因

    前言 本来没有计划这一篇文章的,只是在看完SpringBoot核心原理后,突然想到之前开发中遇到的MVC自动失效的问题,虽然网上有很多文章以及官方文档都说明了原因,但还是想亲自看一看,本以为很简单的事 ...

  5. springboot mvc自动配置(二)注册DispatcherServlet到ServletContext

    所有文章 https://www.cnblogs.com/lay2017/p/11775787.html 正文 上一篇文章中,我们看到了DispatcherServlet和DispatcherServ ...

  6. spring-boot spring-MVC自动配置

    Spring MVC auto-configuration Spring Boot 自动配置好了SpringMVC 以下是SpringBoot对SpringMVC的默认配置:==(WebMvcAuto ...

  7. SpringBoot的自动配置

    1.根据条件来装配bean,SpringBoot的自动配置,根据条件进行自动配置. 首先创建一个接口,如下所示: package com.bie.encoding; /** * * @Descript ...

  8. springboot(六)自动配置原理和@Conditional

    官方参考的配置属性:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-appl ...

  9. 关于SpringBoot的自动配置和启动过程

    一.简介 Spring Boot简化了Spring应用的开发,采用约定大于配置的思想,去繁从简,很方便就能构建一个独立的.产品级别的应用. 1.传统J2EE开发的缺点 开发笨重.配置繁多复杂.开发效率 ...

随机推荐

  1. 面试官问我HTTP,我真的是

    面试官:今天要不来聊聊HTTP吧? 候选者:嗯,HTTP「协议」是客户端和服务器「交互」的一种通迅的格式 候选者:所谓的「协议」实际上就是双方约定好的「格式」,让双方都能看得懂的东西而已 候选者:所谓 ...

  2. vue2项目中引用外部js文件

    vue2项目目录如下(utils文件夹是自己手工建的,然后在utils里新建js文件): 使用import导入文件时,注意路径,路径不对会报错: 导入之后使用外部js函数时,直接写导入时的名字加小括号 ...

  3. GIT Bash 简单讲解-git如何推/拉代码

    GIT Bash 简单讲解 一.            注册/登录GIT账号 注册(或者登录) GitHub地址:https://github.com/ 注册不做详细的讲解,按照注册指示进行注册就可以 ...

  4. Codeforces 571D - Campus(并查集+线段树+DFS 序,hot tea)

    Codeforces 题目传送门 & 洛谷题目传送门 看到集合的合并,可以本能地想到并查集. 不过这题的操作与传统意义上的并查集不太一样,传统意义上的并查集一般是用来判断连通性的,而此题还需支 ...

  5. 【基因组注释】ncRNA注释

    目录 1. ncRNA 2. 软件 tRNA注释 rRNA注释 其他ncRNA注释 3. 注释 tRNA rRNA snRNA.miRNA等 4. snRNA.miRNA等结果的统计 1. ncRNA ...

  6. C++ and OO Num. Comp. Sci. Eng. - Part 3.

    2. Expressions and Statements 声明是将一个种类型的变量引入程序的语句. 作用域 作用域又一对花括号限定,在所有花括号之外的为全局作用域. 在作用域内声明的变量为局部变量. ...

  7. Go 命令类型和未命名类型

    Go 命令类型和未命名类型 例子 package main import "fmt" // 使用type声明的是命令类型 // type new_type old_type typ ...

  8. 利用vcftools比较两个vcf文件

    因为最近有一项工作是比较填充准确性的,中间有用到vcftools比较两个vcf文件. 使用命令也很简单: 1 vcftools --vcf file1.snp.vcf --diff file2.snp ...

  9. (转载)VB中ByVal与ByRef的区别

    ByVal是按值传送,在传的过程中不会改变原来的值,仅仅传送的是一个副本, 而 ByRef相反,从内存地址来说,后者是同一个内存地址. ByVal 与 ByRef(默认值)这两个是子过程的参数传递时, ...

  10. 《手把手教你》系列技巧篇(四十六)-java+ selenium自动化测试-web页面定位toast-下篇(详解教程)

    1.简介 终于经过宏哥的不懈努力,偶然发现了一个toast的web页面,所以直接就用这个页面来夯实一下,上一篇学过的知识-处理toast元素. 2.安居客 事先声明啊,宏哥没有收他们的广告费啊,纯粹是 ...