5.10 MVC自动配置原理
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
andBeanNameViewResolver
beans.- 视图解析器
- Support for serving static resources, including support for WebJars (covered later in this document)).
- 支持静态资源文件夹的路径,以及webjars
- Automatic registration of
Converter
,GenericConverter
, andFormatter
beans.- Converter转换器:网页提交数据到后台自动封装成为对象,比如把"1"字符串自动转换为int类型
- Formatter格式化器:比如页面返回一个2019-8-10,可以自动格式化为Date对象
- Support for
HttpMessageConverters
(covered later in this document).- SpringMVC用来转换Http请求和响应的的
- 比如我们要把一个User对象转换为JSON字符串
- Automatic registration of
MessageCodesResolver
(covered later in this document).- 定义错误代码生成规则
- Static
index.html
support.- 首页定制
- Custom
Favicon
support (covered later in this document).- 图标定制
- Automatic use of a
ConfigurableWebBindingInitializer
bean (covered later in this document).- /初始化数据绑定器:把请求数据绑定到JavaBean中
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
.
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.
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
.
ViewResolver 视图解析器
-
进入WebMvcAutoConfiguration,这是webmvc的配置类,有viewResolver的相关配置
@Bean @ConditionalOnBean(ViewResolver.class) @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class) public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) { ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class)); // ContentNegotiatingViewResolver uses all the other view resolvers to locate // a view so it should have a high precedence // ContentNegotiatingViewResolver使用所有其他视图解析器来定位视图,因此它应该具有较高的优先 resolver.setOrder(Ordered.HIGHEST_PRECEDENCE); return resolver; }
ContentNegotiatingViewResolver获得最高优先级
-
进入
ContentNegotiatingViewResolver类
查看public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {}
可知其实现了
ViewResolver接口
,再看看这个接口吧public interface ViewResolver { /** * Resolve the given view by name. */ @Nullable View resolveViewName(String viewName, Locale locale) throws Exception; }
此接口的核心方法是
resolveViewName
,使用我去看看ContentNegotiatingViewResolver类
如何实现这个方法 -
查看
ContentNegotiatingViewResolver类
的resolveViewName方法
看看如何获取候选视图的,看看
getCandidateViews方法
是从
viewResolvers属性
拿到的,看看这个属性如何初始化把所有的视图解析器从BeanFactory找出来,放进
viewResolvers属性
-
我们自己写一个ViewResolver,注册成bean应该就可以了
// 扩展webmvc配置 @Configuration public class MyMvcConfig implements WebMvcConfigurer { // 将自定义的视图解析器装配 @Bean public ViewResolver myViewResolver() { return new MyViewResolver(); } // 自定义一个视图解析器 public static class MyViewResolver implements ViewResolver { @Override public View resolveViewName(String viewName, Locale locale) throws Exception { return null; } } }
-
调试看看
果然看到了自定义的ViewResolver,并且
ContentNegotiatingViewResolver
是优先级最高的。
FormattingConverter 格式转换器
- 在
WebMvcAutoConfiguration类
里,可以找到格式转换的方法。
-
可以发现这些方法去
WebMvcProperties类
拿到了相应的属性值,熟悉的properties类,也就是说这些值是可以直接配置的,prefix为spring.mvc.format
-
再看一眼
WebMvcProperties类
的结构吧,format
是其中一个静态内部类
修改SpringBoot的默认配置
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ttttt").setViewName("test");
}
跳转成功
扩展原理
-
WebMvcAutoConfiguration类
是 SpringMVC的自动配置类,里面有一个静态内部类WebMvcAutoConfigurationAdapter
-
这个类上有一个注解,在做其他自动配置时会导入:
@Import(EnableWebMvcConfiguration.class)
,点进EnableWebMvcConfiguration类
看一下,它继承了DelegatingWebMvcConfiguration类
可以看到EnableWebMvcConfiguration类
也是WebMvcAutoConfiguration类
的静态内部类
-
看看
DelegatingWebMvcConfiguration类
只有一个属性configurers,类型是WebMvcConfigurerComposite,Composite是拼合的意思,我暂时将其理解为一些WebMvcConfigurer的集合,再点
WebMvcConfigurerComposite类
看看
也只有一个属性,delegates,类型是List<WebMvcConfigurer>
,和我们刚才的猜测基本一致。
delegate意为委托
SpringBoot:最佳英语学习工具
-
回到
DelegatingWebMvcConfiguration类
,找一个方法参考下@Override protected void addViewControllers(ViewControllerRegistry registry) { this.configurers.addViewControllers(registry); }
通过上一步已经知道configurers是
WebMvcConfigurerComposite类
,点开这个方法@Override public void addViewControllers(ViewControllerRegistry registry) { for (WebMvcConfigurer delegate : this.delegates) { delegate.addViewControllers(registry); } }
将所有的WebMvcConfigurer相关配置来一起调用!包括我们自己配置的和Spring给我们配置的
全面接管SpringMVC
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
-annotatedDelegatingWebMvcConfiguration
as described in the Javadoc of@EnableWebMvc
.
使用@EnableWebMvc
可以让SpringBoot的webmvc配置失效
-
看看
@EnableWebMvc
注解如何让自动配置失效@Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { }
导入了
DelegatingWebMvcConfiguration类
,这个类在扩展原理第三步出现了,此类继承了WebMvcConfigurationSupport类
/** * This is the main class providing the configuration behind the MVC Java config. */ public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {}
这是Java方式MVC配置的主类
-
回到
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类
才能让本类生效一旦使用
@EnableWebMvc
,就会使其生效,从而让SpringBoot有关webMVC的自动配置失效