WebMvcConfigurationSupport、WebMvcConfigurerAdapter、WebMvcConfigurer

今天运行一个工程时候发现突然发现以前写的Jackson配置全局过滤值为null的字段的类失效了。这个配置类代码如下:

@Configuration
public class JacksonConfig {
    @Bean
    @Primary
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
        // Include.Include.ALWAYS 默认
        // Include.NON_DEFAULT 属性为默认值不序列化
        // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
        // Include.NON_NULL 属性为NULL 不序列化,就是为null的字段不参加序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 字段保留,将null值转为""
        // objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer() {
        // @Override
        // public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        // jsonGenerator.writeString("");
        // }
        // });
        return objectMapper;
    }
} 
  

排查了半天发现是因为之前将spring boot工程由1.5.10.RELEASE升级到了2.0.1RELEASE,然后IDEA提示拦截器继承的WebMvcConfigurerAdapter类是过时的,就换成了WebMvcConfigurationSupport。改回WebMvcConfigurerAdapter就有效了。非常纳闷于是去网上查了查,大部分都是这样的说明,详见[https://blog.csdn.net/lqadam/article/details/80637335 ]

1.@EnableWebMvc=WebMvcConfigurationSupport,使用了@EnableWebMvc注解等于扩展了WebMvcConfigurationSupport但是没有重写任何方法
2.@EnableWebMvc+extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
3.extends WebMvcConfigurationSupport,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置
4.extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式依旧使用springboot的@EnableAutoConfiguration中的设置

很是不解既然默认配置不是spring boot的一大特色吗,那为什么还有WebMvcConfigurationSupport这种东西。
可能是了解的太少吧,留着这个疑惑慢慢思考,先解决当前的问题。过时的WebMvcConfigurerAdapter带着刺眼的横线,这无疑会污染我的代码,影响编码心情。
查看WebMvcConfigurationAdapter源码,Doc规范告诉我们过时类都会在源码注释中给出推荐使用的替代类。果然发现以下说明:

/**
 * An implementation of {@link WebMvcConfigurer} with empty methods allowing
 * subclasses to override only the methods they're interested in.
 *
 * @author Rossen Stoyanchev
 * @since 3.1
 * @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
 * possible by a Java 8 baseline) and can be implemented directly without the
 * need for this adapter
 */
 @Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
...
}

意思就是Java8给出了新的特性,使得接口方法可以拥有默认实现。所以你现在可以直接实现WebMvcConfigurer而不用像以前那样通过继承它的实现类来达到目的。
OK,文档说的很明白了,换成实现WebMvcConfigurer方式确实解决了问题。

不过新的疑问又出来了,为什么Java8要弄个接口默认方法呢,这有什么特别的地方吗?这个倒是很容易想明白。进入WebMvcConfigurer类查看源码,可以发现其中定义了大量的方法。与WebMvcConfigurerAdapter进行对比可以发现,虽然WebMvcConfigurerAdapter实现了WebMvcConfigurer接口,但是大量的实现都是空实现啊。。。

 ...
@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

    /**
     * {@inheritDoc}
     * 

This implementation is empty. */ @Override public void addCorsMappings(CorsRegistry registry) { } /** * {@inheritDoc} *

This implementation is empty. */ @Override public void addViewControllers(ViewControllerRegistry registry) { } /** * {@inheritDoc} *

This implementation is empty. */ @Override public void configureViewResolvers(ViewResolverRegistry registry) { } ...

做成这样是因为Java的单继承多实现规则,一个类可能同时需要WebMvcConfigurer和其他类中的方法,用继承的方式限制了这一点。而WebMvcConfigurer中的方法也不是在每个地方都会用到,所以写了一些特定场合的适配,这样就可以按需继承对应的适配器,而自己的定制实现通过多态性对外展示为WebMvcConfigurer,使框架能够降低耦合度。
但对于追求完美的编程人员,这显然无法令人满意。于是出现了带有默认实现的接口,这样在使用的时候只需要实现自己想要的方法就行了,不用再去手动空实现或编写适配器。果然懒是第一创造力。

你可能感兴趣的:(SpringMVC)