WebMvcConfigurationSupport 和 WebMvcConfigurer 区别你知道吗

简介: WebMvcConfigurationSupport 和 WebMvcConfigurer 的使用过程中你是否踩坑了它们的区别是什么快来看看吧

👳我亲爱的各位大佬们好

♨️本篇文章记录的为WebMvcConfigurationSupport 和 WebMvcConfigurer相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。
♨️如果文章有什么需要改进的地方还请大佬不吝赐教❤️🧡💛
👨‍🔧 个人主页 : 阿千弟

@[toc]

版本原因

在Spring Boot 1.5版本都是靠重写WebMvcConfigurerAdapter的方法来添加自定义拦截器,消息转换器等。SpringBoot 2.0 后,该类被标记为@Deprecated(弃用)。

在Spring Boot 2.0后用自己的的配置类继承WebMvcConfigurerAdapter时,idea会提示这个类已经过时了。

通常情况下我们会采用下面两种代替方案:

  • 实现WebMvcConfigurer
  • 继承WebMvcConfigurationSupport

在这里插入图片描述

WebMvcConfigurer

为什么WebMvcConfigurer实现要加@EnableWebMvc

  @EnableWebMvc注解类上导入了DelegatingWebMvcConfiguration类,该类是WebMvcConfigurationSupport的子类,该类除了实例化WebMvcConfigurationSupport实例以外,另一个作用就是收集BeanFactory中所有WebMvcConfigurer的实现,汇集到WebMvcConfigurerComposite中,在WebMvcConfigurationSupport实例化过程中会分别调用这些实现,将相应的实例传入这些实现中,供开发者在此基础上添加自定义的配置。这也就是在WebMvcConfigurerAdapter子类上要加@EnableWebMvc的原因,因为要先实例化WebMvcConfigurationSupport

注意:springboot下不需要添加@EnableWebMvc

对于springboot来讲,继承WebMvcConfigure无需再加@EnableWebMvc注解,因为springboot已经实例化了WebMvcConfigurationSupport,如果添加该注解,默认的WebMvcConfigurationSupport配置类是不会生效的,会以用户自定义的为主,一般建议还是不覆盖默认比较好。同时,继承WebMvcConfigurationSupport后,springboot的WebMvc自动配置失效(有可能导致视图解析器无法正常工作)。

### 为什么可以存在多个WebMvcConfigurer的实现?
   一般来讲一个应用中一个WebMvcConfigurer的已经足够,设计成收集多个是不是有些多余?从springboot的autoconfigure机制来看并不多余,反而更灵活,比如我要写一个mybatis的AutoConfiguration和JPA的AutoConfiguration,我就可以在不同的AutoConfiguration里面定义一个WebMvcConfigurer的实现,里面只配置与mybatis或JPA相关的配置,这样需要那个启用那个,不需要人工通过注释代码来转换mybatis和JPA,
### 接口说明
public interface WebMvcConfigurer {
   
   

    void configurePathMatch(PathMatchConfigurer var1);

    void configureContentNegotiation(ContentNegotiationConfigurer var1);

    void configureAsyncSupport(AsyncSupportConfigurer var1);

    void configureDefaultServletHandling(DefaultServletHandlerConfigurer var1);

    void addFormatters(FormatterRegistry var1);

    void addInterceptors(InterceptorRegistry var1);

    void addResourceHandlers(ResourceHandlerRegistry var1);

    void addCorsMappings(CorsRegistry var1);

    void addViewControllers(ViewControllerRegistry var1);

    void configureViewResolvers(ViewResolverRegistry var1);

    void addArgumentResolvers(List<HandlerMethodArgumentResolver> var1);

    void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> var1);

    void configureMessageConverters(List<HttpMessageConverter<?>> var1);

    void extendMessageConverters(List<HttpMessageConverter<?>> var1);

    void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> var1);

    void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> var1);

    Validator getValidator();

    MessageCodesResolver getMessageCodesResolver();
}

常用的方法API

因为现在多用的是前后端分离的项目, 所以前后端不分离的部分方法不再多做阐述

// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
void addInterceptors(InterceptorRegistry var1);
/* 视图跳转控制器 */
void addViewControllers(ViewControllerRegistry registry);
// 这个方法是用来配置静态资源的,比如html,js,css,等等
void addResourceHandlers(ResourceHandlerRegistry registry);
/* 默认静态资源处理器 */
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
/* 这里配置视图解析器*/
void configureViewResolvers(ViewResolverRegistry registry);
/* 配置内容裁决的一些选项*/
void configureContentNegotiation(ContentNegotiationConfigurer configurer);
/** 解决跨域问题 **/
public void addCorsMappings(CorsRegistry registry) ;
//拓展mvc框架的消息转换器
void extendMessageConverters(List<HttpMessageConverter<?>> var1);

addInterceptors:拦截器

@Autowired
    private LoginInterceptor loginInterceptor;
    // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
   
   
        // addPathPatterns("/**") 表示拦截所有的请求,
        // excludePathPatterns("/login", "/register") 表示除了登陆与注册之外,因为登陆注册不需要登陆也可以访问
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**").
                excludePathPatterns("/employee/login", "/employee/register","/backend/**","/front/**");
    }

addViewControllers:页面跳转, 比如登录跳转或错误页面跳转

以前写SpringMVC的时候,如果需要访问一个页面,必须要写Controller类,然后再写一个方法跳转到页面,感觉好麻烦,其实重写WebMvcConfigurer中的addViewControllers方法即可达到效果了

  @Override
    public void addViewControllers(ViewControllerRegistry registry) {
   
   
        registry.addViewController("/toLogin").setViewName("login");

        registry.addViewController("/403").setViewName("/403");
        registry.addViewController("/404").setViewName("/404");
    }

值的指出的是,在这里重写addViewControllers方法,并不会覆盖WebMvcAutoConfiguration(Springboot自动配置)中的addViewControllers(在此方法中,Spring Boot将“/”映射至index.html),这也就意味着自己的配置和Spring Boot的自动配置同时有效,这也是我们推荐添加自己的MVC配置的方式。

extendMessageConverters : 消息转换器

//拓展mvc框架的消息转换器
    @Autowired
    private CustomObjectMapper customObjectMapper;
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
   
   

        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置消息转换器,底层使用jackson将Java对象转成json
        messageConverter.setObjectMapper(customObjectMapper);
        //将我们自定义的消息转换器追加到mvc框架的集合转换器中
        converters.add(0, messageConverter);
    }

在这里插入图片描述

WebMvcConfigurationSupport

WebMvcConfigurationSupport中那些子类可以重写的空方法在WebMvcConfigurer都有,这说明WebMvcConfigurer只是WebMvcConfigurationSupport的一个扩展类,它并没有扩展新功能,只是为让用户更方便安全的添加自定义配置,为什么说是安全呢?

因为如果直接继承WebMvcConfigurationSupport,那么用户可以重写默认的配置,如果对原理不是很清楚地开发者不小心重写了默认的配置,springmvc可能相关功能就无法生效,是一种不安全的行为。

继承WebMvcConfigurationSupport时发现会造成一些问题

先看一下WebMvc自动配置类WebMvcAutoConfiguration的定义:

在这里插入图片描述

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)

看到这行可以明白,原来SpringBoot做了这个限制, 只有当WebMvcConfigurationSupport类不存在的时候才会生效WebMvc自动化配置,WebMvc自动配置类中不仅定义了classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/等路径的映射,还定义了配置文件spring.mvc开头的配置信息等。

继承WebMvcConfigurationSupport会发现Spring Boot的WebMvc自动配置失效(WebMvcAutoConfiguration自动化配置)
如果想要使用自动配置生效,又要按自己的需要重写某些方法,比如增加拦截器。那么将配置类继承WebMvcConfigurationSupport改为实现WebMvcConfigurer接口即可。

在这里插入图片描述

如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对Java后端或者对spring感兴趣的朋友,请多多关注💖💖💖
👨‍🔧 个人主页 : 阿千弟

目录
相关文章
|
6月前
|
索引
for each和for of的区别
for each和for of的区别
for in 和 for of的区别
for in 和 for of的区别
174 1
|
Java
While 与 do while 的区别
While 与 do while 的区别
78 0
||、&&、!的使用与区别
||、&&、!的使用与区别
132 0
|
JSON 数据格式
中writeValue和writeValueAsString的区别
writeValueAsString(obj):将传入的对象序列化为json,返回给调用者
|
算法 编译器 Linux
C与C++的区别
C与C++的区别
123 0
<T>和<?>区别
简要讲述一下<T>和<?>区别,以及<T>的用法
<T>和<?>区别
@EnableEurekaClient上有@EnableDiscoveryClient区别
@EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient 可以是其他注册中心。
936 0