Spring-boot下自定義JsonSerializer時(shí)間序列化器導(dǎo)致數(shù)組越界記錄

問題現(xiàn)象

Spring-boot框架下項(xiàng)目。測試環(huán)境下部署的項(xiàng)目怎么測試都沒有發(fā)現(xiàn)有任何問題,當(dāng)部署到生產(chǎn)環(huán)境中時(shí),開始也不會(huì)有什么問題,但是在人多獲取一些偶然情況下,就出現(xiàn)問題,導(dǎo)致涉及到該接口的數(shù)據(jù)不能獲取到,其他接口正常獲取。然后調(diào)用log日記文件發(fā)現(xiàn)里面報(bào)了一個(gè)錯(cuò)誤:
  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排查
看到這個(gè)錯(cuò)誤,第一眼關(guān)注到 java.lang.ArrayIndexOutOfBoundsException覺得是哪個(gè)數(shù)組數(shù)據(jù)越界了,但是我沒有進(jìn)行任何賦值操作啊。
查看第二條com.fasterxml.jackson.databind.JsonMappingException異常,覺得可能是JSON轉(zhuǎn)換導(dǎo)致的數(shù)據(jù)異常,查看資料,詢問朋友,有人說是fastjson讀取數(shù)據(jù)過大導(dǎo)致,json序列化出錯(cuò)。然后我查看我是用的JSON解析,是使用spring-boot內(nèi)置的JackSon解析器的,應(yīng)該不會(huì)吧。同時(shí)因?yàn)榉?wù)器內(nèi)存不大,所以開始還以為是讀取大數(shù)據(jù)時(shí),導(dǎo)致的內(nèi)存不足,因?yàn)榭紤]到序列化需要使用內(nèi)存,但是本地測試獲取更多的數(shù)據(jù)發(fā)現(xiàn)還是可以成功。最后查看modifyTime的序列化問題,然后追查最終原因,終于發(fā)現(xiàn)問題了
問題根源,問題代碼
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);                 
        }
    }
 } 

因?yàn)樽约鹤远x一個(gè)日期的序列化器,查看JDK API說明SimpleDateFormat是一個(gè)非線程安全的類,而在進(jìn)行時(shí)間序列化時(shí),只能同時(shí)只有一個(gè)線程可以進(jìn)行序列化,如果這是用戶請(qǐng)求有序列化的數(shù)據(jù)過多,導(dǎo)致服務(wù)器在同一時(shí)間內(nèi)分配多個(gè)線程來同時(shí)進(jìn)行序列化操作,這是就超出可用的線程組,也就是上面提示的數(shù)組越界的本質(zhì)原因。

處理方案
日期序列化解析器出現(xiàn)問題,如果是JKD 8.0 可以使用線程安全的DateTimeFormatter來替代SimpleDateFormat,或者在進(jìn)行序列化時(shí)加上同步操作,下面是一種做法
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);                 
        }
    }
  }
}

實(shí)現(xiàn)同步線程控制,來實(shí)現(xiàn)自定義日期序列化器在高并發(fā)情況下正常運(yùn)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • 在一個(gè)方法內(nèi)部定義的變量都存儲(chǔ)在棧中,當(dāng)這個(gè)函數(shù)運(yùn)行結(jié)束后,其對(duì)應(yīng)的棧就會(huì)被回收,此時(shí),在其方法體中定義的變量將不...
    Y了個(gè)J閱讀 4,573評(píng)論 1 14
  • 昨夜晚間看了一場老電影《滾滾紅塵》,大時(shí)代下隨波逐流的愛情與被裹挾的命運(yùn)充滿了懷舊氣息。至今在華語文壇上最特立獨(dú)行...
    傲嬌的混混兒閱讀 324評(píng)論 0 0
  • 我嘗試找答案 而答案很簡單, 簡單得很遺憾, 因?yàn)槌砷L 我們逼不得已要習(xí)慣, 因?yàn)槌砷L 我們忽爾間說散就散。
    dlsss閱讀 221評(píng)論 0 0
  • 古人說,讀萬卷書,行萬里路。其實(shí)旅行也是一種閱讀是認(rèn)識(shí)世界的另一種方式。 黃河壺口的瀑布雖沒有李白的“飛流直下三千...
    為為道來閱讀 511評(píng)論 0 3

友情鏈接更多精彩內(nèi)容