SpringBoot中有大量的自动配置,而SpringMVC自动配置属于关键的部分
https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications
查看官方文档
可看出Spring Boot 自动配置好了SpringMVC,而以上罗列的内容是SpringBoot对SpringMVC的默认配置。
接下来,详细介绍每一条的内容:
自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(所谓的渲染是指是否转发?是否重定向?))
我们来看一下源码,首先是搜索一下WebMvcAutoConfiguration类(MVC自动配置类)
进入后,再搜索ContentNegotiatingViewResolver,即视图解析器
我们可以进入视图解析器,在里面找到 resolveViewName(),这是真正进行试图解析的方法
在这个方法里面,有两个核心的方法:getCandidateViews()和getBestView()
getCandidateViews(),用来获取候选视图
getBestView(),用以获取最适合的视图
我们先进入getCandidateViews()方法里面看看:
因此,我们可以总结出来,ContentNegotiatingViewResolver是用以组合所有的视图解析器的。
那我们如何定制呢:我们可以自己给容器中添加一个视图解析器,ContentNegotiatingViewResolver就会自动地将其组合进来;
我们可以来实战看看是否真的是这么一回事。
首先,我们先在代码中实现一个ViewResolver类型的方法,同时声明一个实现了ViewResolver接口的内部类:
之后我们搜索dispatcherservlet类
进入后,我们搜索doDispatch()方法。所有请求一进来,会先进入这个方法
静态资源文件夹路径,即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这个转换器类的值
getBeansOfType()这个方法我们也可以点进去看看:
我们可以看到这个方法本质上是个容器,于是思考:我们能否自己添加转化器呢?答案是可以!自己添加的格式化器转换器,我们只需要放在容器中即可。
1、Support for HttpMessageConverters (see below).
针对上述的HttpMessageConverter是如何配的呢?我们可以看看源码:
首先,我们在WebMvcAutoConfiguration类中寻找HttpMessageConverters
我们再看看WebMvcAutoConfigurationAdapter()这个方法,其中有一个参数如下:
需要注意的是,如果只有一个有参构造器的情况下,每一个参数的值都是需要从容器中拿到的。相当于HttpMessageConverters如何确定值,是要从容器中拿的。因此总结出第二条:
我们来看看这个HttpMessageConverters到底是个啥,点进去!
可以看到里面都是一些有参构造器,而这些有参构造器要么从数组取值,要么是从集合中取。
换言之,如果自己给容器中添加HttpMessageConverter,仍是刚才那句话,只需要将自己的组件注册容器中(用@Bean或者@Component均可)
我们可以在官方文档中查看到这点:
绿框是说,如果我们需要添加或者定制化一些converters,那我们可以使用Spring Boot的HttpMessageConverters类
1、Automatic registration of MessageCodesResolver (see below):定义错误代码生成规则
上源码,先搜索MessageCodesResolver
我们注意到,它还能从一个配置类里面取配置。
我们可以点击getMessageCodesResolverFormat()进入这个配置里面窥其一二:
这个配置返回了一个messageCodesResolverFormat,点击进入,发现有一个format
点击这个fromat进行查看:
发现这是一个枚举类,里面罗列的是错误码生成规则!
1、Automatic use of a ConfigurableWebBindingInitializer bean (see below).
找到它之后,我们分析源码,发现其实也是在容器中取值
这告诉我们,我们可以配置一个ConfigurableWebBindingInitializer来替换默认的(要给容器中添加组件,因此需要添加到容器)
继续分析代码,如下代码含义是指,如果拿不到值,那就返回父类的
我们可以看看返回了父类的什么:
原来是创造一个Initializer,这个的作用是初始化web数据绑定器,这个绑定器的功能是将请求数据绑定到JavaBean
我们可以再来看看ConfigurableWebBindingInitializer
点进去之后,找到 initBinder()方法,其作用便是初始化web数据绑定器
通过以上的系列代码分析,我们可以发现:
以上仅仅是分析了WebMVC自动配置,因此自动配置可不仅仅是这些;
Springboot对整个web的配置,我们都可以在项目中找到:
在web模块中发现有很多自动配置类,其都是对web方面进行的自动配置
org.springframework.boot.autoconfigure.web:web的所有自动场景
以上的很多内容我们很难理解,但是我们是想通过以上的分析对这种固定模式有所了解:
即如何修改SpringBoot的默认配置,我们总结出如下的模式套路:
注意,这个模式不仅能用于web模块,其他模块也一样受用!
模式:
1、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)
如果有就用用户配置的,如果没有,才自动配置;
如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;当然,这不是所有的情况,正如官方文档所言:
译文:如果你想保持springboot对MVC的配置功能,并且我们又想添加一些额外的MVC配置,那我们就可以编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型;而且还不能标注@EnableWebMvc
接下来我们实践一下,如何扩展这个功能
扩展与全面接管SpringMVC
1、扩展SpringMVC
首先我们新建一个类,例如MyConfig,编写如下代码:
代码部分主要是实现了WebMvcConfigurer接口,这是最新的做法,视频中的做法是继承:
而WebMvcConfigurer这个接口内部则是众多的空方法,在我们实现这个接口时,可以自定义方法的内容:
在MyConfig类内部是重写了addViewControllers(),用以添加视图控制器。即我们在url输入“test”,应当访问的是“success”页面
注意,这是扩展springmvc,既保留了所有的自动配置,也能用我们扩展的配置。那么其原理又是怎样的呢?
原理:
1、WebMvcAutoConfiguration是SpringMVC的自动配置类
我们发现其中有一个WebMvcAutoConfigurationAdapter类,它是实现了WebMvcConfigurer这个接口
我们重点看一下这个类的头部,有一个@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
因此,我们可以得出第二条重要信息:
2)、在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)
点击进入EnableWebMvcConfiguration.class类,发现其是继承了DelegatingWebMvcConfiguration这个类,
我们看看这个父类:
在头部有 @Autowired注解,说明方法的参数需要从容器中获取。
setConfigurers()中定义了一个List类型的参数,而这个方法的作用便是从容器中获取所有的WebMvcConfigurer
在这个类里面还有一些配置方法,要注意噢,这些都是调用的configurers的方法
例如添加视图映射,addViewControllers(),它调的是addViewControllers()方法
进入addViewControllers()看看,
这两行关键代码的作用是将所有的WebMvcConfigurer相关配置都拿来一起调用,即一起起作用,所以我们得出第三点:
3)、容器中所有的WebMvcConfigurer都会一起起作用;
4)、我们的配置类也会被调用;
效果:SpringMVC的自动配置和我们的扩展配置都会起作用;
当然,仍然不要忘记还有这个条件:
Buuuuuuuuuuuut!!!!!
于是由此引出第三大点,即全面接管SpringMVC
3、全面接管SpringMVC
SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了
我们需要在配置类中添加@EnableWebMvc即可;
当添加了@EnableWebMvc注解后,相当于开启springmvc的全面接管,那么之前的springmvc的自动配置就会全部失效,实践的最好对象就是静态资源。可以简单来实践一下。
我们在主程序类头部添加@EnableWebMvc注解
控制台也对此有输出信息:
那么全面接管的原理又是什么呢?
原理:
为什么@EnableWebMvc自动配置就失效了;
1、@EnableWebMvc的核心
里面导入了DelegatingWebMvcConfiguration.class文件,那就点进去看看吧
我们发现这个类真的似曾相识,点这里!(P13)
再来看看为什么这个类把对应模块给整失效了呢?那就需要我们再来看看WebMvcAutoConfiguration的头部了,其中有一个即为关键的语句:
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
这是用来判断容器中没有这个组件的时候,这个自动配置类才生效。
嘿嘿嘿,有点意思,因为刚才我们看到,在@EnableWebMvc这个注解里面,正是导入了WebMvcConfigurationSupport这个类