問題現(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)行。