美文网首页
Spring-boot下自定义JsonSerializer时间序

Spring-boot下自定义JsonSerializer时间序

作者: 雨中漫步的北极熊 | 来源:发表于2018-06-29 13:36 被阅读32次

    问题现象

    Spring-boot框架下项目。测试环境下部署的项目怎么测试都没有发现有任何问题,当部署到生产环境中时,开始也不会有什么问题,但是在人多获取一些偶然情况下,就出现问题,导致涉及到该接口的数据不能获取到,其他接口正常获取。然后调用log日记文件发现里面报了一个错误:
      Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: 
      Could not write content: (was java.lang.ArrayIndexOutOfBoundsException) (through reference chain: 
      com.maigang.mgb2b.model.TypePageData["brandlist"]->java.util.ArrayList[71]-
      >com.maigang.mgb2b.entity.Brand["modifyTime"]); nested exception is 
      com.fasterxml.jackson.databind.JsonMappingException: (was 
      java.lang.ArrayIndexOutOfBoundsException) (through reference chain: 
      com.maigang.mgb2b.model.TypePageData["brandlist"]->java.util.ArrayList[71]-
      >com.maigang.mgb2b.entity.Brand["modifyTime"])
    
    BUG排查
    看到这个错误,第一眼关注到 java.lang.ArrayIndexOutOfBoundsException觉得是哪个数组数据越界了,但是我没有进行任何赋值操作啊。
    查看第二条com.fasterxml.jackson.databind.JsonMappingException异常,觉得可能是JSON转换导致的数据异常,查看资料,询问朋友,有人说是fastjson读取数据过大导致,json序列化出错。然后我查看我是用的JSON解析,是使用spring-boot内置的JackSon解析器的,应该不会吧。同时因为服务器内存不大,所以开始还以为是读取大数据时,导致的内存不足,因为考虑到序列化需要使用内存,但是本地测试获取更多的数据发现还是可以成功。最后查看modifyTime的序列化问题,然后追查最终原因,终于发现问题了
    问题根源,问题代码
    public class JsonDateSerializer2 extends JsonSerializer<Date> {
    private SimpleDateFormat dateFormat = new SimpleDateFormat(
            "yyyy-MM-dd");
    @Override
    public void serialize(Date date, JsonGenerator gen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
            if(date == null){
                gen.writeStartArray();
                gen.writeEndArray();
            } else {
                String value = dateFormat.format(date);
                gen.writeString(value);                 
            }
        }
     } 
    

    因为自己自定义一个日期的序列化器,查看JDK API说明SimpleDateFormat是一个非线程安全的类,而在进行时间序列化时,只能同时只有一个线程可以进行序列化,如果这是用户请求有序列化的数据过多,导致服务器在同一时间内分配多个线程来同时进行序列化操作,这是就超出可用的线程组,也就是上面提示的数组越界的本质原因。

    处理方案
    日期序列化解析器出现问题,如果是JKD 8.0 可以使用线程安全的DateTimeFormatter来替代SimpleDateFormat,或者在进行序列化时加上同步操作,下面是一种做法
    public class JsonDateSerializer2 extends JsonSerializer<Date> {
    private SimpleDateFormat dateFormat = new SimpleDateFormat(
            "yyyy-MM-dd");
    
    @Override
    public void serialize(Date date, JsonGenerator gen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
        synchronized (dateFormat) {
            if(date == null){
                gen.writeStartArray();
                gen.writeEndArray();
            } else {
                String value = dateFormat.format(date);
                gen.writeString(value);                 
            }
        }
      }
    }
    

    实现同步线程控制,来实现自定义日期序列化器在高并发情况下正常运行。

    相关文章

      网友评论

          本文标题:Spring-boot下自定义JsonSerializer时间序

          本文链接:https://www.haomeiwen.com/subject/wtxayftx.html