標籤:指定 字串 需要 載入 json反序列 dde 重複 動態 create
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版本
談談fastjson反序列方法JSON.parseObject(String text, Class<T> clazz)--來源於生產實踐