SpringBoot——MVC自动配置原理

806 阅读5分钟

springboot为springmvc提供了自动配置,可以很好地用于大多数应用程序。

这些自动配置在Spring默认设置的基础上进行了扩展,可以参考springboot官方文档。

文档链接:docs.spring.io/spring-boot…

下面内容截取自官方文档,很详细的说明了pringboot为springmvc自动装配了什么功能,然后又扩展了哪些功能,并且如何使用扩展的功能:

// 自动配置在Spring默认设置的基础上添加了以下功能:
The auto-configuration adds the following features on top of Spring’s defaults:

// 包含视图解析器
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
    
// 支持静态资源文件夹的路径,以及webjars
Support for serving static resources, including support for WebJars 
    
//自动注册了Converter: 转换器,这就是我们网页提交数据到后台自动封装成为对象的东西,比如把"1"字符串自动转换为int类型
// Formatter:格式化器,比如页面给我们了一个2019-8-10,它会给我们自动格式化为Date对象
Automatic registration of Converter, GenericConverter, and Formatter beans.
    
// HttpMessageConverters
// SpringMVC用来转换Http请求和响应的的,比如我们要把一个User对象转换为JSON字符串;
Support for HttpMessageConverters (covered later in this document).
    
// 定义错误代码生成规则的
Automatic registration of MessageCodesResolver (covered later in this document).
    
// 首页定制
Static index.html support.
    
// 图标定制
Custom Favicon support (covered later in this document).
    
// 初始化数据绑定器:帮我们把请求数据封装到JavaBean中!
Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
    
    

    
//=================================扩展mvc功能============================
/*
如果您希望保留Spring Boot MVC功能,并且希望添加其他MVC配置(拦截器、格式化程序、视图控制器和其他功能),则可以添加自己的@configuration类,类型为webmvcconfiguer,但不添加@EnableWebMvc。如果希望提供RequestMappingHandlerMapping、RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义实例,则可以声明WebMVCregistrationAdapter实例来提供此类组件。
*/
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration 
(interceptors, formatters, view controllers, and other features), you can add your own 
@Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide 
custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or 
ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

// 如果您想完全控制Spring MVC,可以添加自己的@Configuration,并用@EnableWebMvc进行注释。
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

1、ContentNegotiatingViewResolver配置原理

以前在SpringMVC中,视图解析器我们需要在resources目录下的applicationContext.xml文件中手动配置,如下所示:

<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
      id="internalResourceViewResolver">
    <!-- 前缀 -->
    <property name="prefix" value="/WEB-INF/jsp/" />
    <!-- 后缀 -->
    <property name="suffix" value=".jsp" />
</bean>

但在springboot中,已经帮springmvc自动装配了ContentNegotiatingViewResolver类,ContentNegotiatingViewResolver视图解析器是Spring MVC 中常用的一个视图解析器。

ContentNegotiatingViewResolver类的源码如下:

public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
      implements ViewResolver, Ordered, InitializingBean {
//只要实现了视图解析器ViewResolver的类就可以看做视图解析器

ContentNegotiatingViewResolver重写ViewResolver接口的方法,源码如下:

在这里插入图片描述

获取候选的视图的具体实现是怎么样的呢?点进去继续分析源码:

在这里插入图片描述

所以:

编写配置类手动实现视图解析器

package com.cheng.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Locale;

//扩展springmvc的配置
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    //注入到spring中
    @Bean
    public ViewResolver myViewResolver(){
        return new MyViewResolver();
    }

    //自定义一个视图解析器,只要实现了视图解析器ViewResolver的类就可以看做视图解析器
    public static class MyViewResolver implements ViewResolver{

        @Override
        public View resolveViewName(String viewName, Locale locale) throws Exception {
            return null;
        }
    }
}

我们想查看自定义的视图解析器有没有起作用,只要在DispatcherServlet类的doDisoatch方法上打个断点,然后启动SpringBoot程序,随便访问一个页面,debug一下

在这里插入图片描述

发现我们自定义的视图解析器起作用了

总结:

  • ContentNegotiatingViewResolver这个视图解析器就是用来组合所有的视图解析器的,它会返回最合适的视图解析器,所以ContentNagotiatingViewResolver自己并不解析视图,而是委派给其他的视图解析器。

  • 如果我们想自定义一些功能,只要写这个组件,然后将它交给springboot,springboot会帮我们自动装配!

2、配置格式化转换器

配置Formatter格式转换器

格式化器在application.properties中的配置:

@Deprecated
@DeprecatedConfigurationProperty(replacement = "spring.mvc.format.date")
public String getDateFormat() {
   return this.format.getDate();
}

测试:

#默认日期格式
spring.mvc.format.date=dd/MM/yyyy 
#自定义日期格式
spring.mvc.format.date=dd-MM-yyyy 

SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(如果用户自己配置@bean),如果有就用用户配置的,如果没有就用自动配置的;

如果有些组件可以存在多个,比如我们的视图解析器,就将用户配置的和自己默认的组合起来!

3、配置视图控制器

package com.cheng.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Locale;

//扩展springmvc的配置
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    //增加视图控制器
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

        //输入cheng请求,就会跳转到test.html页面
        registry.addViewController("/cheng").setViewName("test");
    }
}

启动测试,成功跳转!

4、@EnableWebMvc

在官方文档中有这样一句话:如果想扩展springmvc的配置,可以添加自己的webmvcconfiguer类型的@configuration类,但不添加@EnableWebMvc。

现在来分析一下,为什么不能加上@EnableWebMvc呢?

首先看一下@EnableWebMvc的组成:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

@EnableWebMvc只导入了一个DelegatingWebMvcConfiguration类,点进去分析DelegatingWebMvcConfiguration

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

DelegatingWebMvcConfiguration又继承了WebMvcConfigurationSupport这个类;

我们再看一下WebMvcAutoConfiguration(自动装配MVC)的源码:

@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这个类的时候,mvc的自动配置会失效,所以不能加@EnableWebMvc