SpringBoot---初探MVC自动配置原理

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 and BeanNameViewResolver beans.
    • 视图解析器
  • Support for serving static resources, including support for WebJars (covered later in this document)).
    • 支持静态资源文件夹的路径,以及webjars
  • Automatic registration of Converter, GenericConverter, and Formatter 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 视图解析器

  1. 进入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获得最高优先级

  2. 进入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类如何实现这个方法

  3. 查看ContentNegotiatingViewResolver类resolveViewName方法

    看看如何获取候选视图的,看看getCandidateViews方法

    是从viewResolvers属性拿到的,看看这个属性如何初始化

    把所有的视图解析器从BeanFactory找出来,放进viewResolvers属性

  4. 我们自己写一个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;
            }
        }
    }
    
  5. 调试看看

    果然看到了自定义的ViewResolver,并且ContentNegotiatingViewResolver是优先级最高的。

FormattingConverter 格式转换器

  1. WebMvcAutoConfiguration类里,可以找到格式转换的方法。

  1. 可以发现这些方法去WebMvcProperties类拿到了相应的属性值,熟悉的properties类,也就是说这些值是可以直接配置的,prefix为spring.mvc.format

  2. 再看一眼WebMvcProperties类的结构吧,format是其中一个静态内部类

修改SpringBoot的默认配置

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/ttttt").setViewName("test");
}

跳转成功

扩展原理

  1. WebMvcAutoConfiguration类 是 SpringMVC的自动配置类,里面有一个静态内部类WebMvcAutoConfigurationAdapter

  2. 这个类上有一个注解,在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class),点进EnableWebMvcConfiguration类看一下,它继承了DelegatingWebMvcConfiguration类

可以看到EnableWebMvcConfiguration类也是WebMvcAutoConfiguration类 的静态内部类

  1. 看看DelegatingWebMvcConfiguration类

    只有一个属性configurers,类型是WebMvcConfigurerComposite,Composite是拼合的意思,我暂时将其理解为一些WebMvcConfigurer的集合,再点WebMvcConfigurerComposite类看看

也只有一个属性,delegates,类型是List<WebMvcConfigurer>,和我们刚才的猜测基本一致。

delegate意为委托

SpringBoot:最佳英语学习工具

  1. 回到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-annotated DelegatingWebMvcConfiguration as described in the Javadoc of @EnableWebMvc.

使用@EnableWebMvc可以让SpringBoot的webmvc配置失效

  1. 看看@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配置的主类

  2. 回到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 {}
    
  3. 注意看第四行--->@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

    这是一个条件判断,没有WebMvcConfigurationSupport类才能让本类生效

    一旦使用@EnableWebMvc,就会使其生效,从而让SpringBoot有关webMVC的自动配置失效

猜你喜欢

转载自www.cnblogs.com/antonzhao/p/13191738.html