前言

最近项目组用feign调用近程服务,生产端报了如下一个异样

从异样信息能够得出localdatime反序列化出了异样,而这个异样又是因为jackson无奈解决导致。因而咱们能够为jackson的ObjectMapper适配一下

解决办法

1、在pom.xml引入
    <dependency>                <groupId>com.fasterxml.jackson.datatype</groupId>                <artifactId>jackson-datatype-jsr310</artifactId>                <version>${jackson.version}</version>            </dependency>            <dependency>                <groupId>com.fasterxml.jackson.datatype</groupId>                <artifactId>jackson-datatype-jdk8</artifactId>                <version>${jackson.version}</version>            </dependency>

注: jackson-datatype-jsr310这是用来反对jsr310标准的工夫,jackson-datatype-jdk8用来反对新的特定于JDK8的类型,例如Optional

2、替换默认的ObjectMapper
@Configurationpublic class LocalDateTimeConfig  {    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";      @Bean    public ObjectMapper objectMapper() {        ObjectMapper objectMapper = new ObjectMapper();        objectMapper.registerModule(new Jdk8Module());        objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT));        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);        objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);        JavaTimeModule javaTimeModule = new JavaTimeModule();        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));        objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule());        return objectMapper;    }

疑难点:为什么替换了默认的ObjectMapper后,feign就能够解决LocalDateTime

答案就在

@Configuration(proxyBeanMethods = false)public class FeignClientsConfiguration {    @Autowired    private ObjectFactory<HttpMessageConverters> messageConverters;    @Bean    @ConditionalOnMissingBean    public Decoder feignDecoder() {        return new OptionalDecoder(                new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));    }}

而messageConverters默认的转换器是依据HttpMessageConvertersAutoConfiguration而来

@Configuration(proxyBeanMethods = false)@ConditionalOnClass(HttpMessageConverter.class)@Conditional(NotReactiveWebApplicationCondition.class)@AutoConfigureAfter({ GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class })@Import({ JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class,        JsonbHttpMessageConvertersConfiguration.class })public class HttpMessageConvertersAutoConfiguration {    static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper";    @Bean    @ConditionalOnMissingBean    public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {        return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));    }

ObjectProvider具备提早加载的性能,会依据理论状况加载。springboot的web模块默认会引入Jackson相干包。官网上有这么一段话

这个就阐明默认的HttpMessageConverter为MappingJackson2HttpMessageConverter,而MappingJackson2HttpMessageConverter会利用objectMapper来进行序列化和反序列化

下面的的话用代码整顿如下

 public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";    @Bean    public Decoder feignDecoder() {        return new ResponseEntityDecoder(new SpringDecoder(messageConverters()));    }    public ObjectFactory<HttpMessageConverters> messageConverters() {        return () -> new HttpMessageConverters(mappingJackson2HttpMessageConverter());    }    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {        return new MappingJackson2HttpMessageConverter(objectMapper());    }    public ObjectMapper objectMapper() {        ObjectMapper objectMapper = new ObjectMapper();        objectMapper.registerModule(new Jdk8Module());        objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT));        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);        objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);        JavaTimeModule javaTimeModule = new JavaTimeModule();        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));        objectMapper.registerModule(javaTimeModule).registerModule(new ParameterNamesModule());        return objectMapper;    }

总结

异样信息很重要,源码很重要,官网同样重要