从源码层次了解SpringBoot中SpringMVC的自动配置原理

SpringBoot中有大量的自动配置,而SpringMVC自动配置属于关键的部分

https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications

查看官方文档

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第1张图片

可看出Spring Boot 自动配置好了SpringMVC,而以上罗列的内容是SpringBoot对SpringMVC的默认配置。

接下来,详细介绍每一条的内容:

1)Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(所谓的渲染是指是否转发?是否重定向?))

我们来看一下源码,首先是搜索一下WebMvcAutoConfiguration类(MVC自动配置类)

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第2张图片

 

进入后,再搜索ContentNegotiatingViewResolver,即视图解析器

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第3张图片

 

我们可以进入视图解析器,在里面找到   resolveViewName(),这是真正进行试图解析的方法

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第4张图片

 

在这个方法里面,有两个核心的方法:getCandidateViews()和getBestView()

getCandidateViews(),用来获取候选视图

getBestView(),用以获取最适合的视图

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第5张图片

 

我们先进入getCandidateViews()方法里面看看:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第6张图片

 

因此,我们可以总结出来,ContentNegotiatingViewResolver是用以组合所有的视图解析器的

那我们如何定制呢:我们可以自己给容器中添加一个视图解析器,ContentNegotiatingViewResolver就会自动地将其组合进来;

我们可以来实战看看是否真的是这么一回事。

首先,我们先在代码中实现一个ViewResolver类型的方法,同时声明一个实现了ViewResolver接口的内部类:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第7张图片

 

之后我们搜索dispatcherservlet类

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第8张图片

 

进入后,我们搜索doDispatch()方法。所有请求一进来,会先进入这个方法

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第9张图片

 

2)Support for serving static resources, including support for WebJars (see below).

静态资源文件夹路径,即webjars(之前已讲)

1、Automatic registration of Converter, GenericConverter, Formatter beans.

自动注册Converter(转换器):类型转换使用。例如public String hello(User user),但是页面传来一个18(年纪)

Formatter:格式化器:格式转化。例如2020/9/8 ==Date

同样地,我们可以在WebMvcAutoConfiguration类中找到如下方法(当然新版没有这个方法了)

接下来在这个类里面继续查看addFormatters()方法

 

再进入ApplicationConversionService,寻找一下addBeans(),在这个方法里面,我们发现getBeansOfType()这个方法获取Converter这个转换器类的值

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第10张图片

 

getBeansOfType()这个方法我们也可以点进去看看:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第11张图片

我们可以看到这个方法本质上是个容器,于是思考:我们能否自己添加转化器呢?答案是可以!自己添加的格式化器转换器,我们只需要放在容器中即可。

1、Support for HttpMessageConverters (see below).

  • HttpMessageConverter:SpringMVC用来转换Http请求和响应的;User---Json;

针对上述的HttpMessageConverter是如何配的呢?我们可以看看源码:

 

首先,我们在WebMvcAutoConfiguration类中寻找HttpMessageConverters

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第12张图片

 

我们再看看WebMvcAutoConfigurationAdapter()这个方法,其中有一个参数如下:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第13张图片

需要注意的是,如果只有一个有参构造器的情况下,每一个参数的值都是需要从容器中拿到的。相当于HttpMessageConverters如何确定值,是要从容器中拿的。因此总结出第二条:

  • HttpMessageConverters 是从容器中确定;底层原理即是获取所有的HttpMessageConverter

 

我们来看看这个HttpMessageConverters到底是个啥,点进去!

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第14张图片

可以看到里面都是一些有参构造器,而这些有参构造器要么从数组取值,要么是从集合中取。

换言之,如果自己给容器中添加HttpMessageConverter,仍是刚才那句话,只需要将自己的组件注册容器中(用@Bean或者@Component均可)

我们可以在官方文档中查看到这点:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第15张图片

绿框是说,如果我们需要添加或者定制化一些converters,那我们可以使用Spring Boot的HttpMessageConverters类

1、Automatic registration of MessageCodesResolver (see below):定义错误代码生成规则

上源码,先搜索MessageCodesResolver

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第16张图片

 

我们注意到,它还能从一个配置类里面取配置。

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第17张图片

我们可以点击getMessageCodesResolverFormat()进入这个配置里面窥其一二:

这个配置返回了一个messageCodesResolverFormat,点击进入,发现有一个format

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第18张图片

点击这个fromat进行查看:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第19张图片

发现这是一个枚举类,里面罗列的是错误码生成规则!

1、Automatic use of a ConfigurableWebBindingInitializer bean (see below).

找到它之后,我们分析源码,发现其实也是在容器中取值

这告诉我们,我们可以配置一个ConfigurableWebBindingInitializer来替换默认的(要给容器中添加组件,因此需要添加到容器)

继续分析代码,如下代码含义是指,如果拿不到值,那就返回父类的

我们可以看看返回了父类的什么:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第20张图片

原来是创造一个Initializer,这个的作用是初始化web数据绑定器,这个绑定器的功能是将请求数据绑定到JavaBean

 

我们可以再来看看ConfigurableWebBindingInitializer

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第21张图片

点进去之后,找到 initBinder()方法,其作用便是初始化web数据绑定器

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第22张图片

 

通过以上的系列代码分析,我们可以发现:

以上仅仅是分析了WebMVC自动配置,因此自动配置可不仅仅是这些;

Springboot对整个web的配置,我们都可以在项目中找到:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第23张图片

在web模块中发现有很多自动配置类,其都是对web方面进行的自动配置

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第24张图片

org.springframework.boot.autoconfigure.web:web的所有自动场景

以上的很多内容我们很难理解,但是我们是想通过以上的分析对这种固定模式有所了解:

即如何修改SpringBoot的默认配置,我们总结出如下的模式套路:

注意,这个模式不仅能用于web模块,其他模块也一样受用!

模式:

1、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)

如果有就用用户配置的,如果没有,才自动配置;

如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;当然,这不是所有的情况,正如官方文档所言:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第25张图片

译文:如果你想保持springboot对MVC的配置功能,并且我们又想添加一些额外的MVC配置,那我们就可以编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型;而且还不能标注@EnableWebMvc

 

接下来我们实践一下,如何扩展这个功能

扩展与全面接管SpringMVC

1、扩展SpringMVC

 

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第26张图片

 

首先我们新建一个类,例如MyConfig,编写如下代码:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第27张图片

代码部分主要是实现了WebMvcConfigurer接口,这是最新的做法,视频中的做法是继承:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第28张图片

而WebMvcConfigurer这个接口内部则是众多的空方法,在我们实现这个接口时,可以自定义方法的内容:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第29张图片

 

在MyConfig类内部是重写了addViewControllers(),用以添加视图控制器。即我们在url输入“test”,应当访问的是“success”页面

 

 

注意,这是扩展springmvc,既保留了所有的自动配置,也能用我们扩展的配置。那么其原理又是怎样的呢?

原理:

1、WebMvcAutoConfiguration是SpringMVC的自动配置类

我们发现其中有一个WebMvcAutoConfigurationAdapter类,它是实现了WebMvcConfigurer这个接口

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第30张图片

 

我们重点看一下这个类的头部,有一个@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第31张图片

因此,我们可以得出第二条重要信息:

2)、在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)

点击进入EnableWebMvcConfiguration.class类,发现其是继承了DelegatingWebMvcConfiguration这个类,

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第32张图片

我们看看这个父类:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第33张图片

在头部有 @Autowired注解,说明方法的参数需要从容器中获取。

setConfigurers()中定义了一个List类型的参数,而这个方法的作用便是从容器中获取所有的WebMvcConfigurer

 

在这个类里面还有一些配置方法,要注意噢,这些都是调用的configurers的方法

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第34张图片

例如添加视图映射,addViewControllers(),它调的是addViewControllers()方法

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第35张图片

 

进入addViewControllers()看看,

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第36张图片

这两行关键代码的作用是将所有的WebMvcConfigurer相关配置都拿来一起调用,即一起起作用,所以我们得出第三点:

 

 3)、容器中所有的WebMvcConfigurer都会一起起作用;

 4)、我们的配置类也会被调用;

效果:SpringMVC的自动配置和我们的扩展配置都会起作用;

当然,仍然不要忘记还有这个条件:

Buuuuuuuuuuuut!!!!!

于是由此引出第三大点,即全面接管SpringMVC

3、全面接管SpringMVC

SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了

我们需要在配置类中添加@EnableWebMvc即可;

 

当添加了@EnableWebMvc注解后,相当于开启springmvc的全面接管,那么之前的springmvc的自动配置就会全部失效,实践的最好对象就是静态资源。可以简单来实践一下。

 

我们在主程序类头部添加@EnableWebMvc注解

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第37张图片

 

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第38张图片

 

控制台也对此有输出信息:

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第39张图片

 

那么全面接管的原理又是什么呢?

原理:

为什么@EnableWebMvc自动配置就失效了;

1、@EnableWebMvc的核心

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第40张图片

 

里面导入了DelegatingWebMvcConfiguration.class文件,那就点进去看看吧

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第41张图片

我们发现这个类真的似曾相识,点这里!(P13)

 

再来看看为什么这个类把对应模块给整失效了呢?那就需要我们再来看看WebMvcAutoConfiguration的头部了,其中有一个即为关键的语句:

@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})

这是用来判断容器中没有这个组件的时候,这个自动配置类才生效。从源码层次了解SpringBoot中SpringMVC的自动配置原理_第42张图片

 

 

嘿嘿嘿,有点意思,因为刚才我们看到,在@EnableWebMvc这个注解里面,正是导入了WebMvcConfigurationSupport这个类

 

从源码层次了解SpringBoot中SpringMVC的自动配置原理_第43张图片

 

你可能感兴趣的:(SpringBoot,java)