fastjson這一工具包幫助我們進行java對象和json格式的字元串之間的相互轉換。對象到字元串的過程,我們稱之為序列化;反之,我們稱為反序列化。 現在我們就來談談fastjson提供的反序列化方法,本篇只討論按照指定的位元組碼返回相應對象的的反序列化方法,該方法有多種重載形式,按照重疊構造的模式 ...
fastjson這一工具包幫助我們進行java對象和json格式的字元串之間的相互轉換。對象到字元串的過程,我們稱之為序列化;反之,我們稱為反序列化。
現在我們就來談談fastjson提供的反序列化方法,本篇只討論按照指定的位元組碼返回相應對象的的反序列化方法,該方法有多種重載形式,按照重疊構造的模式設計。常用的入口為:JSON.parseObject(String text, Class<T> clazz),其調用鏈為:
JSON.parseObject(String text, Class<T> clazz) --> parseObject(String text, Class<T> clazz, Feature... features) --> parseObject(String input, Type clazz, ParserConfig config, int featureValues, Feature... features) --> parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor, int featureValues, Feature... features)
這樣最終實際調用的方法及其參數值為:parseObject(input, clazz, ParserConfig.getGlobalInstance(), null, DEFAULT_PARSER_FEATURE, new Feature[0])。
我們關註下ParserConfig.getGlobalInstance(),每次調用返回同一個ParserConfig對象。這樣其實保證了以JSON.parseObject(String text, Class<T> clazz)為入口的場景下,ParserConfig對象的全局唯一,即所謂的單例。
我們看看ParserConfig對象在fastjson反序列化過程中的作用:
作用一:維護了常用類型和反序列化器之間的對應關係,存放到IdentityHashMap<Type, ObjectDeserializer>中,並可通過getDeserializer(Type type)方法獲得對象反序列化器ObjectDeserializer;對於非預定義好的類型,拿到該類型的反序列化器的同時,並建立該類型和相應反序列化器的對應關係,存放到IdentityHashMap<Type, ObjectDeserializer>中,以便後續直接使用;
作用二:創建欄位反序列化器FieldDeserializer,而這些FieldDeserializer會維護到ObjectDeserializer的IdentityHashMap<String, FieldDeserializer>中,其中key為欄位名稱。
重點關註FieldDeserializer的生成,通過源碼分析,通常情況下會調用ASMDeserializerFactory.getInstance().createFieldDeserializer(parserConfig, clazz, fieldInfo)生成欄位反序列化器。
if (fieldClass == int.class || fieldClass == long.class || fieldClass == String.class) {
return createStringFieldDeserializer(mapping, clazz, fieldInfo);
}
通過上面createFieldDeserializer中的源碼可以看出,針對int、long和String類型做了特殊處理,進一步分析發現其內部利用asm位元組碼增加技術對IntegerFieldDeserializer、LongFieldDeserializer以及StringFieldDeserializer做了擴展,動態生成了新的類。
類名為:String name = "Fastjson_ASM__Field_" + clazz.getSimpleName();
name += "_" + fieldInfo.getName() + "_" + seed.incrementAndGet();(註意seed此種場景下是單例的)
該類主要是新增了setValue()方法,應該是用來對欄位進行賦值操作的(PS:關於對象序列化和欄位序列化器的內部處理邏輯有機會可進一步分析研究)
綜上:針對保留了永久代的jvm,對於如上三種類型的欄位,在創建FieldDeserializer時會動態生成新的類,造成jvm載入的類的數目上升,永久代記憶體的增加。當然通常情況,一個項目中需要反序列化的類是有限的,並且因為常用情況下ParseConfig是單例,相應欄位對應的欄位序列化器類生成一份後就不在重覆生成了,永久代記憶體通常情況下也就不會溢出。
JSON.parseObject ( reqMsg, ReqMsgDto.class, new ParserConfig() , JSONObject.DEFAULT_PARSER_FEATURE )
但若如上進行api的調用,此種情況下ParserConfig不在全局唯一,就可能會持續不斷的生成欄位序列化器類,從而造成java.lang.OutOfMemoryError: PermGen space。此種場景下應將ParserConfig的實例作為類變數或者成員變數,以避免每次調用都會創建新的欄位序列化類。
備註:fastjson源碼分析基於1.1.37版本