記一次踩坑:springboot2.0.2配置fastjson不生效

最近在嘗試搭建springboot+dubbo+shiro基於註解的一個項目,突發奇想一想把消息轉換器從jackson換成fastjson,因而就開始了折騰之路.java

輕車熟路的去自定了一個SpringMvcConfigure去繼承WebMvcConfigurerAdapter,而後就發現這個WebMvcConfigurerAdapter居然過期了?what?點進去看源碼:web

/**
 * 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 {}

能夠看到從spring5.0開始就被@Deprecated,原來是java8中支持接口中有默認方法,因此咱們如今能夠直接實現WebMvcConfigurer,而後選擇性的去重寫某個方法,而不用實現它的全部方法.spring

因而就實現了WebMvcConfigurer:json

@Configuration
public class SpringMvcConfigure implements WebMvcConfigurer {

    /**
     * 配置消息轉換器
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        //自定義配置...
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
                SerializerFeature.WriteEnumUsingToString,
                /*SerializerFeature.WriteMapNullValue,*/
                SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.DisableCircularReferenceDetect);
        fastJsonHttpMessageConverter.setFastJsonConfig(config);
        converters.add(fastJsonHttpMessageConverter);
    }

}

本覺得這樣子配置就能夠完事兒,可是詭異的事情發生了,我明明註釋了SerializerFeature.WriteMapNullValue,但是返回的json中仍然有爲null的字段,而後我就去com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter中的writewriteInternal打了斷點,再次執行,居然什麼都沒有發生,根本沒有走這兩個方法,因而在自定義的SpringMvcConfigureconfigureMessageConverters方法內打了斷點,想看看這個方法參數converters裏邊到底有什麼:
convertersapi

看到這裏就想到,確定是我本身添加的fastjson在後邊,因此沒有生效,因此就加了如下代碼:springboot

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters = converters.stream()
                .filter((converter)-> !(converter instanceof MappingJackson2HttpMessageConverter))
                .collect(Collectors.toList());
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
    //自定義配置...
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
            SerializerFeature.WriteEnumUsingToString,
            /*SerializerFeature.WriteMapNullValue,*/
            SerializerFeature.WriteDateUseDateFormat,
            SerializerFeature.DisableCircularReferenceDetect);
    fastJsonHttpMessageConverter.setFastJsonConfig(config);
    converters.add(fastJsonHttpMessageConverter);
}

居然尚未生效,後來開始追蹤,開始方法是從org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport類中的一個bean配置:mvc

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
    adapter.setContentNegotiationManager(mvcContentNegotiationManager());
    //就是從這裏開始設置converters的,而後從這裏一路追蹤下去.
    adapter.setMessageConverters(getMessageConverters());
    adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
    adapter.setCustomArgumentResolvers(getArgumentResolvers());
    adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

    if (jackson2Present) {
        adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
        adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
    }

    AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
    configureAsyncSupport(configurer);
    if (configurer.getTaskExecutor() != null) {
        adapter.setTaskExecutor(configurer.getTaskExecutor());
    }
    if (configurer.getTimeout() != null) {
        adapter.setAsyncRequestTimeout(configurer.getTimeout());
    }
    adapter.setCallableInterceptors(configurer.getCallableInterceptors());
    adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

    return adapter;
}

getMessageConverters()方法:app

protected final List<HttpMessageConverter<?>> getMessageConverters() {
    if (this.messageConverters == null) {
        this.messageConverters = new ArrayList<>();
        configureMessageConverters(this.messageConverters);//進入這一步
        if (this.messageConverters.isEmpty()) {
            addDefaultHttpMessageConverters(this.messageConverters);
        }
        extendMessageConverters(this.messageConverters);
    }
    return this.messageConverters;
}

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration:ide

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    this.configurers.configureMessageConverters(converters);
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.configureMessageConverters(converters);
    }
}

this.delegates包含了springboot的一個默認配置類類:org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration裏邊有一個參數this

private final HttpMessageConverters messageConverters;

for循環裏的delegate.configureMessageConverters(converters)調用了WebMvcAutoConfiguration中的configureMessageConverters方法:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.addAll(this.messageConverters.getConverters());
}

執行完這個後,就給converters中添加了10個轉換器了,就是上圖中的10個.
this.delegates中還有一個就是咱們自定義的那個,執行完後,在咱們自定義的那個SpringMvcConfigure發現我添加的fastjson添加進去了,可是org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.getMessageConverters(),發現converters並無發現咱們添加進去的FastJsonHttpMessageConverter,這時忽然又想起來:java8的stream api每次都是生成一個新的對象,因此致使converters已經不是傳遞過來的那個converters的引用了(這裏也證實了java是值傳遞,不是引用傳遞).

因而再次改變那個lambda表達式爲普通的加強for循環:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    /*converters = converters.stream().
            filter((converter)-> !(converter instanceof MappingJackson2HttpMessageConverter))
            .collect(Collectors.toList());*/
    for (HttpMessageConverter<?> converter : converters) {
        if (converter instanceof MappingJackson2HttpMessageConverter){
            converters.remove(converter);
        }
    }
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
    //自定義配置...
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
            SerializerFeature.WriteEnumUsingToString,
            /*SerializerFeature.WriteMapNullValue,*/
            SerializerFeature.WriteDateUseDateFormat,
            SerializerFeature.DisableCircularReferenceDetect);
    fastJsonHttpMessageConverter.setFastJsonConfig(config);
    converters.add(fastJsonHttpMessageConverter);
}

再次運行,wtf?報錯了:ConcurrentModificationException,原來使用for循環遍歷過程當中不能進行remove操做,因而換成Iterator:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    /*converters = converters.stream()
            .filter((converter)-> !(converter instanceof MappingJackson2HttpMessageConverter))
            .collect(Collectors.toList());
    for (HttpMessageConverter<?> converter : converters) {
        if (converter instanceof MappingJackson2HttpMessageConverter){
            converters.remove(converter);
        }
    }*/
    Iterator<HttpMessageConverter<?>> iterator = converters.iterator();
    while(iterator.hasNext()){
        HttpMessageConverter<?> converter = iterator.next();
        if(converter instanceof MappingJackson2HttpMessageConverter){
            iterator.remove();
        }
    }
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
    //自定義配置...
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
            SerializerFeature.WriteEnumUsingToString,
            /*SerializerFeature.WriteMapNullValue,*/
            SerializerFeature.WriteDateUseDateFormat,
            SerializerFeature.DisableCircularReferenceDetect);
    fastJsonHttpMessageConverter.setFastJsonConfig(config);
    converters.add(fastJsonHttpMessageConverter);
}

再次運行,我去,終於解決了,先是刪除MappingJackson2HttpMessageConverter,而後添加FastJsonHttpMessageConverter,可是不是到爲何進過一系列操做後,MappingJackson2HttpMessageConverter仍是添加進去了,可是因爲FastJsonHttpMessageConverterMappingJackson2HttpMessageConverter以前添加,因此對結果不影響.至此,解決了這個問題.

總結

  1. 最重要的仍是解決了springboot2.0.2配置fastjson不生效的問題
  2. 更加明白stream api返回的都是全新的對象
  3. 更理解java是值傳遞而不是引用傳遞
  4. 瞭解到想要在迭代過程當中對集合進行操做要用Iterator,而不是直接簡單的for循環或者加強for循環

若有不正確的地方還請指出,謝謝.

相關文章
相關標籤/搜索