한 번 의 구덩이 밟 기: springboot 2.0.2 설정 fastjson 이 유효 하지 않 습 니 다.

최근 에는 spring boot + dubbo + shiro 가 주 해 를 바탕 으로 하 는 프로젝트 를 만 들 려 고 시도 하고 있 습 니 다. 갑자기 메시지 변환 기 를 jackson 에서 fastjson 으로 바 꾸 려 고 하 자 괴 롭 히 기 시 작 했 습 니 다.
가 벼 운 차 로 하 나 를 정 했다 SpringMvcConfigure 계승 WebMvcConfigurerAdapter. 그리고 이것 WebMvcConfigurerAdapter 이 시대 에 뒤떨어 졌 다 는 것 을 알 게 되 었 다.what?입력 하여 원본 코드 보기:
/**
 * 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 {}

spring 5.0 부터 @ Deprecated 를 볼 수 있 습 니 다. 자바 8 에서 지원 하 는 인터페이스 에 기본 적 인 방법 이 있 었 기 때문에 우 리 는 지금 WebMvcConfigurer 을 직접 실현 한 다음 에 선택 적 으로 어떤 방법 을 다시 쓸 수 있 습 니 다. 모든 방법 을 실현 하지 않 아 도 됩 니 다.
그래서 실현 되 었 다 WebMvcConfigurer.
@Configuration
public class SpringMvcConfigure implements WebMvcConfigurer {

    /**
     *        
     * @param converters
     */
    @Override
    public void configureMessageConverters(List> 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 을 달 았 습 니 다. 그러나 돌아 온 제 이 슨 에는 아직도 위 null 필드 가 있 습 니 다. 그리고 저 는 com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter 중의 writewriteInternal 정지점 에 가서 다시 실 행 했 습 니 다. 아무 일 도 일어나 지 않 았 습 니 다. 이 두 가지 방법 을 전혀 가지 지 않 았 습 니 다. 그래서 사용자 정의 SpringMvcConfigure 에서 configureMessageConverters방법 내 에 단점 을 쳤 습 니 다. 이 방법 파라미터 converters 안에 무엇이 있 는 지 보고 싶 습 니 다.
여기 서 보 니 제 가 추가 한 fastjson 이 뒤에 있 기 때문에 효력 이 발생 하지 않 았 습 니 다. 그래서 다음 과 같은 코드 를 추 가 했 습 니 다.
@Override
public void configureMessageConverters(List> 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 설정 입 니 다.
@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() 방법:
protected final List> 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 :
@Override
protected void configureMessageConverters(List> converters) {
    this.configurers.configureMessageConverters(converters);
}
@Override
public void configureMessageConverters(List> converters) {
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.configureMessageConverters(converters);
    }
}

this. delegates 는 springboot 의 기본 설정 클래스 를 포함 합 니 다. org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration 안에 인자 가 있 습 니 다.
private final HttpMessageConverters messageConverters;

for 순환 중의 delegate.configureMessageConverters(converters) 호출 WebMvcAutoConfiguration 중의 configureMessageConverters 방법:
@Override
public void configureMessageConverters(List> converters) {
    converters.addAll(this.messageConverters.getConverters());
}

이것 을 실행 한 후에 converters10 개의 컨버터 를 추 가 했 습 니 다. 바로 위의 그림 에 있 는 10 개 입 니 다. this.delegates 중 하 나 는 우리 가 사용자 정의 한 것 입 니 다. 실행 한 후에 우리 가 사용자 정의 한 것 SpringMvcConfigure 에서 내 가 추가 한 fastjson 이 추 가 된 것 을 발 견 했 습 니 다. 그러나 org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.getMessageConverters() converters 는 우리 가 추가 한 것 FastJsonHttpMessageConverter 을 발견 하지 못 했 습 니 다.이때 갑자기 생각 났 습 니 다. 자바 8 의 stream api 는 매번 새로운 대상 을 만 들 기 때문에 converters 는 이미 전 달 된 그 converters 의 인용 이 아 닙 니 다 (여기 서도 자바 가 값 전달 임 을 증명 합 니 다. 인용 전달 이 아 닙 니 다).
그래서 그 lambda 표현 식 을 일반적인 증강 for 순환 으로 다시 바 꿉 니 다:
@Override
public void configureMessageConverters(List> 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> converters) {
    /*converters = converters.stream()
            .filter((converter)-> !(converter instanceof MappingJackson2HttpMessageConverter))
            .collect(Collectors.toList());
    for (HttpMessageConverter> converter : converters) {
        if (converter instanceof MappingJackson2HttpMessageConverter){
            converters.remove(converter);
        }
    }*/
    Iterator> 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 추가 되 었 습 니까? 그러나 FastJsonHttpMessageConverter 이전에 추가 되 었 기 때문에 결과 에 영향 을 주지 않 았 습 니 다. 이로써 이 문 제 를 해결 하 였 습 니 다.
총결산
  • 가장 중요 한 것 은 springboot 2.0.2 설정 fastjson 이 적용 되 지 않 는 문 제 를 해결 하 는 것 입 니 다
  • stream api 가 돌아 오 는 것 은 모두 새로운 대상 임 을 더욱 잘 알 수 있다
  • 자바 가 인용 전달 이 아니 라 값 전달 이라는 것 을 더 이해한다
  • 교체 과정 에서 집합 을 조작 하려 면 Iterator 를 사용 해 야 한 다 는 것 을 알 게 되 었 습 니 다. 직접적 으로 간단 한 for 순환 이나 증강 for 순환
  • 이 아 닙 니 다.
    잘못된 점 이 있 으 면 지적 해 주세요. 감사합니다.

    좋은 웹페이지 즐겨찾기