测试报bug说传入的生日时间戳是651078000000(对应时间是1990-08-20 00:00:00),但是存在数据库是1990-08-19,事关我写的微服务,便决定查一下。
feign.SynchronousMethodHandler
的第90行代码Response response;
try {
response = this.client.execute(request, this.options);
} catch (IOException var15) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var15, this.elapsedTime(start));
}
throw FeignException.errorExecuting(request, var15);
}
response = this.client.execute(request, this.options);
这一行打一个断点,请求的时候查一下request的数据,发现出去时就错了,我了个去,然后单步调试发现序列化器用的是jackson,原来配置了fastjson序列化器没生效,去了解了一下feign这个项目发现feign使用的httpconverter和springMVC的不是同一个,于是配置feign的序列化和反序列化器:
@Configuration
public class MyFeignClientsConfiguration {
@Bean
public Encoder feignEncoder(){
return new SpringEncoder(feignHttpMessageConverter());
}
@Bean
public Decoder feignDecoder(){
return new SpringDecoder(feignHttpMessageConverter());
}
/**
*feign和Springboot使用的都是jackson,可以都修改为fastjson解析方式
*/
private ObjectFactory<HttpMessageConverters> feignHttpMessageConverter(){
final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(this.getFastJsonConverter());
return () -> httpMessageConverters;
}
private FastJsonHttpMessageConverter getFastJsonConverter(){
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
List<MediaType> supportedMediaTypes = new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
supportedMediaTypes.add(MediaType.APPLICATION_PDF);
supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XML);
supportedMediaTypes.add(MediaType.IMAGE_GIF);
supportedMediaTypes.add(MediaType.IMAGE_JPEG);
supportedMediaTypes.add(MediaType.IMAGE_PNG);
supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
supportedMediaTypes.add(MediaType.TEXT_XML);
converter.setSupportedMediaTypes(supportedMediaTypes);
FastJsonConfig config = new FastJsonConfig();
config.getSerializeConfig().put(JSON.class,new SwaggerJsonSerializer());
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
converter.setFastJsonConfig(config);
return converter;
}
}
期间还遇到一个什么content-type不能包含*
的错误,通过手动组建supportedMediaTypes
数组解决。
在feign的调用方和服务提供方都添加上上面的配置后,还是有问题,具体表现在feign的调用request中日期是时间戳,并没有问题,feign的服务提供方能接收到调用方传过来的数据,是时间戳,没问题,但是通过SimpleDateFormate输出后还是有问题,这就不得不怀疑SimpleDateFormate的时区用的啥,SimpleDateFormate的时区默认是GMT,后面发现了有人在SpringBoot启动的时候设置了时区:
TimeZone.getTimeZone("GMT+8")
问题估计就出在这了,查git,发现是某个同事,于是去问了一下原因,得到的解释是logback在客户机上输出的时间不对,所以设置了时区。我晕,想吐槽:日志时间不对去搞logback啊,全局设置时区影响整个服务啊,再说了,日志时间不对和生产数据不对,哪个比较重要?这用屁股想想都优先生产数据。于是果断删除时区设置。
logback配置文件中pattern
有:
%d [%thread] %-5p [%c] [%F:%L] [trace=%X{X-B3-TraceId:-},span=%X{X-B3-SpanId:-},parent=%X{X-B3-ParentSpanId:-}] - %msg%n
去翻了一下logback的文档,http://logback.qos.ch/manual/layouts.html
,
根据第二个框的描述,.SSS
是可以配置为时区的,于是改pattern
为:
%date{yyyy-MM-dd HH:mm:ss.SSS,Asia/Shanghai} [%thread] %-5p [%c] [%F:%L] [trace=%X{X-B3-TraceId:-},span=%X{X-B3-SpanId:-},parent=%X{X-B3-ParentSpanId:-}] - %msg%n
耗时一天加一上午解决,如果不设置全局时区的话,这个问题可能就只停留在logback了,别轻易修改全局配置。
今天又爆出了上面的问题,查了一下午,发现在入库前prepareStatment的setDate之前是可以的,之后就不行了,怀疑是mybatis框架使用SimpleDateFormat使用时区混乱,从操作系统,到docker容器,到应用JVM,到数据库,时区是真的混乱,不care操作系统,docker容器,我在JVM级别定住时区,在Spring Boot启动类添加(上面的logback那不用动,保持上面的代码就好):
final TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
TimeZone.setDefault(timeZone);
尽量使用上海时区,GMT+8
有时候会出现在当前时间基础上加8小时问题