從 JSON 字符串到 Java 對象:Fastjson 1.2.83 全程解析
一、概述
二、核心模塊架構
三、項目結構
1. 項目結構說明
2. 項目結構小結
四、核心源碼分析
1. 序列化原理介紹
2. 序列化小結
3. 反序列化流程
4. 反序列化小結
五、特性講解
1. ASM性能優化
2. AutoType機制
3. 流式解析
六、總結
一、概述
Fastjson 是阿里巴巴開源的高性能 JSON 序列化處理庫,其主要以處理小數據時速度最快而著稱,功能全面。Fastjson1.X版本目前已停止維護,被Fastjson2.X代替,但1.X版本國內被廣泛使用,通過學習其技術架構,剖析架構上優缺點,對技術人員提升軟件設計工程實踐能力很有價值。
首先我們對“序列化 / 反序列化”概念上建立直觀認識,把Java對象轉化為JSON格式的字符串的過程叫做序列化操作,反之則叫反序列化。如果把“序列化 / 反序列化”放到整個計算機系統的坐標系里,可以把它看成一次數據的“跨邊界搬家”。
對象在“內存世界”里活得很好,但只要一離開進程地址空間(網絡、磁盤、數據庫、瀏覽器、異構語言),就必須先打成包裹(序列化),到對岸再拆包裹(反序列化)。
圖片
二、核心模塊架構
從高層次視圖看Fastjson框架的結構,主要可以分為用戶接口層、配置管理層、序列化引擎、反序列化引擎和安全防護層。其中用戶接口提供了門面類用戶編碼直接與門面類交互,降低使用復雜度;配置管理層允許用戶對框架行為進行配置;序列化引擎是序列化操作的核心實現;反序列引擎是反序列化操作的核心實現;安全模塊解決框架安全問題,允許用戶針對安全問題設置黑白名單等安全檢查功能。下圖為Fastjson模塊關系圖:
模塊關系圖
三、項目結構
com.alibaba.fastjson/
├── JSON.java # 核心入口類
├── annotation/ # 注解定義
├── asm/ # ASM字節碼精簡庫
├── parser/ # 解析器模塊
│ ├── DefaultJSONParser.java # 默認JSON解析器
│ ├── JSONLexer.java # 詞法分析器接口
│ ├── JSONScanner.java # 詞法分析器實現
│ └── deserializer/ # 反序列化器
├── serializer/ # 序列化器模塊
│ ├── JSONSerializer.java # JSON序列化器
│ ├── SerializeConfig.java # 序列化配置
│ └── ObjectSerializer.java # 對象序列化器接口
├── spi/ # SPI擴展機制
├── support/ # 框架支持
└── util/ # 工具類項目結構說明
主要可以劃分為以下幾個核心模塊(包):
com.alibaba.fastjson (核心 API 與數據結構)
- 關鍵類 :
JSON.java: 整個庫的門面(Facade),提供了最常用、最便捷的靜態方法,如 toJSONString() (序列化), parseObject() (反序列化為對象), parseArray() (反序列化為數組)。通常它是用戶最先接觸到的類。
JSONObject.java: 繼承自java.util.HashMap,用于表示 JSON 對象結構( {key: value} )。
JSONArray.java: 繼承自java.util.ArrayList,用于表示 JSON 數組結構 ( [value1, value2] )。
com.alibaba.fastjson.serializer (序列化模塊)
此模塊負責將 Java 對象轉換為 JSON 格式的字符串
- 關鍵類 :
JSONSerializer.java: 序列化的核心調度器。它維護了序列化的上下文信息,如對象引用、循環依賴檢測、特性( SerializerFeature )開關等,并驅動整個序列化過程。
SerializeWriter.java: 一個高度優化的 Writer 實現,專門用于生成 JSON 字符串。它內部使用 char[] 數組來拼接字符串,避免了 String 的不可變性帶來的性能損耗,是 Fastjson 高性能寫入的關鍵。
JavaBeanSerializer.java: 默認的 JavaBean 序列化器。在未啟用 ASM 優化時,它通過反射獲取對象的屬性( getter 方法)并將其序列化。
ASMSerializerFactory.java: 性能優化的核心 。它使用 ASM 字節碼技術在運行時動態生成序列化器類,這些類直接調用 getter 方法并操作SerializeWriter,避免了反射的性能開銷。
ObjectSerializer.java: 序列化器接口。用戶可以通過實現此接口來為特定類型提供自定義的序列化邏輯。
SerializeConfig.java: 序列化配置類。它維護了 Java 類型到 ObjectSerializer 的緩存。 SerializeConfig.getGlobalInstance() 提供了全局唯一的配置實例。
SerializerFeature.java: 序列化特性枚舉。定義了各種序列化行為的開關,例如 WriteMapNullValue (輸出 null 值的字段)、 DisableCircularReferenceDetect (禁用循環引用檢測) 等。
com.alibaba.fastjson.parser (反序列化模塊)
此模塊負責將 JSON 格式的字符串解析為 Java 對象。
- 關鍵類 :
DefaultJSONParser.java: 反序列化的核心調度器。它負責解析 JSON 字符串的整個過程,管理 JSONLexer進行詞法分析,并根據 Token (如 { , } , [ , ] , string , number 等)構建 Java 對象。
JSONLexer.java / JSONLexerBase.java: JSON 詞法分析器。它負責掃描輸入的 JSON 字符串,將其切割成一個個有意義的 Token ,供 DefaultJSONParser 使用。
JavaBeanDeserializer.java: 默認的 JavaBean 反序列化器。在未啟用 ASM 優化時,它通過反射創建對象實例并設置其屬性值。
ASMDeserializerFactory.java: 與序列化類似,它動態生成反序列化器字節碼,直接調用 setter 方法或直接對字段賦值,避免了反射。
ObjectDeserializer.java: 反序列化器接口。用戶可以實現此接口來自定義特定類型的反序列化邏輯。
ParserConfig.java: 反序列化配置類。維護了 Java 類型到 ObjectDeserializer 緩存,并負責管理 ASM 生成的類的加載。
Feature.java: 反序列化特性枚舉,用于控制解析行為。
com.alibaba.fastjson.annotation (注解模塊)
提供了一系列注解,允許用戶通過聲明式的方式精細地控制序列化和反序列化的行為。
- 關鍵注解 :
@JSONField: 最核心的注解,可用于字段或方法上,用于自定義字段名、格式化、序列化/反序列化順序、是否包含等。
@JSONType: 可用于類上,用于配置該類的序列化器、反序列化器、特性開關等。
項目結構小結
Fastjson 框架在架構設計體現了“關注點分離”的原則,將序列化、反序列化、API、工具類等清晰地劃分到不同的模塊中。整個框架具有高度的可擴展性,用戶可以通過 ObjectSerializer / ObjectDeserializer接口和豐富的注解來滿足各種復雜的定制化需求。
四、核心源碼分析
為了更直觀說明框架實現原理,本文對部分展示的源代碼進行了刪減,有些使用了偽代碼,如需了解更多實現細節請讀者閱讀項目源碼(https://github.com/alibaba/fastjson)
整體上Fastjson通過統一的門面API(JSON.toJSONString/parseObject)調用核心控制器(JSONSerializer/DefaultJSONParser),利用ASM字節碼生成或反射機制,配合SerializeWriter/JSONLexer進行高效的Java對象與JSON字符串間雙向轉換,同時提供配置緩存、循環引用檢測和AutoType安全防護等優化機制。下圖為框架處理數據流:
數據流
序列化原理介紹
序列化步驟主要包括:序列化器查找→JavaBean字段解析→字段值轉換和JSON字符串構建等過程。下圖為序列化處理時序圖:
序列化時序圖
序列化入口與初始化
使用JSON.toJSONString()入口,將person對象轉換為JSON字符串。
Person person = new Person();
String json = JSON.toJSONString(person);用戶調用toJSONString方法進行對象序列化操作,JSON.java包含了多個toJSONString重載方法,共同完成核心類初始化:SerializeConfig,SerializeWriter,JSONSerializer。
//用戶不指定SerializeConfig,默認私有全局配置
public static String toJSONString(Object object, SerializeFilter[] filters,
SerializerFeature... features) {
return toJSONString(object, SerializeConfig.globalInstance, filters, null, DEFAULT_GENERATE_FEATURE, features);
}
public static String toJSONString(Object object,
SerializeConfig config,
SerializeFilter[] filters,
String dateFormat,
int defaultFeatures,
SerializerFeature... features) {
SerializeWriter out = new SerializeWriter((Writer) null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out);
//省略其他代碼...
serializer.write(object); // 核心序列化調用
return out.toString();
} finally {
out.close();
}
}序列化控制流程
JSONSerializer.write()核心邏輯
write方法的邏輯比較簡單,首先處理null值,然后根據類型查找序列器(ObjectSerializer),最后將序列化邏輯委派給序列化器處理。
public final void write(Object object) {
//如何序列化對象為null,直接寫入"null"字符串
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz); // 類型識別與序列化器選擇
try {
writer.write(this, object, null, null, 0); // 委托給具體序列化器
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}類型識別與序列化器策略
框架采用策略化模式將不同類型序列化邏輯封裝成不同的序列化器:
- 基礎類型 : 使用專門的Codec(如StringCodec、IntegerCodec)
- 集合類型 : 使用ListSerializer、MapSerializer等
- JavaBean : 使用JavaBeanSerializer或ASM動態生成的序列化器
- 枚舉類型 : 使用EnumSerializer
SerializeConfig.getObjectWriter方法負責序列化器查找工作:
public ObjectSerializer getObjectWriter(Class<?> clazz, boolean create) {
// 第一步:緩存查找
ObjectSerializer writer = get(clazz);
if (writer != null) {
return writer;
}
// 第二步:SPI擴展加載(當前線程類加載器)
try {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
if (!(o instanceof AutowiredObjectSerializer)) {
continue;
}
AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
for (Type forType : autowired.getAutowiredFor()) {
put(forType, autowired);
}
}
} catch (ClassCastException ex) {
// skip
}
writer = get(clazz);
if (writer == null) {
// 第三步:SPI擴展加載(JSON類加載器)
final ClassLoader classLoader = JSON.class.getClassLoader();
if (classLoader != Thread.currentThread().getContextClassLoader()) {
// 重復SPI加載邏輯...
}
}
// 第四步:模塊擴展
for (Module module : modules) {
writer = module.createSerializer(this, clazz);
if (writer != null) {
put(clazz, writer);
return writer;
}
}
// 第五步:內置類型匹配
if (writer == null) {
String className = clazz.getName();
Class<?> superClass;
if (Map.class.isAssignableFrom(clazz)) {
put(clazz, writer = MapSerializer.instance);
} else if (List.class.isAssignableFrom(clazz)) {
put(clazz, writer = ListSerializer.instance);
} else if (Collection.class.isAssignableFrom(clazz)) {
put(clazz, writer = CollectionCodec.instance);
} else if (Date.class.isAssignableFrom(clazz)) {
put(clazz, writer = DateCodec.instance);
} else if (clazz.isEnum()) {
// 枚舉處理邏輯
} else if (clazz.isArray()) {
// 數組處理邏輯
} else {
// 第六步:JavaBean序列化器創建
if (create) {
writer = createJavaBeanSerializer(clazz);
put(clazz, writer);
}
}
}
return writer;
}JavaBean序列化處理
JavaBeanSerializer的write方法實現了Java對象序列化處理核心邏輯:
方法簽名分析:
protected void write(JSONSerializer serializer, //JSON序列化器,提供序列化上下文和輸出流
Object object, //待序列化的Java對象
Object fieldName, //字段名稱,用于上下文追蹤
Type fieldType, //字段類型信息
int features, //序列化特性標志位
boolean unwrapped //是否展開包裝,用于嵌套對象處理
) throws IOException序列化流程概覽:
// 1. 空值檢查和循環引用處理
if (object == null) {
out.writeNull();
return;
}
if (writeReference(serializer, object, features)) {
return;
}
// 2. 字段序列化器選擇
final FieldSerializer[] getters;
if (out.sortField) {
getters = this.sortedGetters;
} else {
getters = this.getters;
}
// 3. 上下文設置和格式判斷
SerialContext parent = serializer.context;
if (!this.beanInfo.beanType.isEnum()) {
serializer.setContext(parent, object, fieldName, this.beanInfo.features, features);
}
// 4.遍歷屬性序列化器,完成屬性序列化
for (int i = 0; i < getters.length; ++i) {
FieldSerializer fieldSerializer = getters[i];
// 獲取屬性值
Object propertyValue = this.processValue(serializer, fieldSerializer.fieldContext, object, fieldInfoName,
propertyValue, features);
// 寫入屬性值
fieldSerializer.writeValue(serializer, propertyValue);
}循環引用檢測:
JavaBeanSerializerwriteReference 方法執行循環引用檢測,Fastjson使用$ref占位符處理循環引用問題,防止對象循環引用造成解析查詢棧溢出。
public boolean writeReference(JSONSerializer serializer, Object object, int fieldFeatures) {
SerialContext context = serializer.context;
int mask = SerializerFeature.DisableCircularReferenceDetect.mask;
// 檢查是否禁用循環引用檢測
if (context == null || (context.features & mask) != 0 || (fieldFeatures & mask) != 0) {
return false;
}
// 檢查對象是否已存在于引用表中
if (serializer.references != null && serializer.references.containsKey(object)) {
serializer.writeReference(object); // 寫入引用標記
return true;
}
return false;
}上下文管理與引用追蹤:
序列化采用DFS(深度優先)算法遍歷對象樹,使用 IdentityHashMap<Object, SerialContext> references 來追蹤對象引用:
- setContext: 建立序列化上下文,記錄對象層次關系
- containsReference: 檢查對象是否已被序列化
- popContext: 序列化完成后清理上下文
protected IdentityHashMap<Object, SerialContext> references = null;
protected SerialContext context;
//使用鏈表建立序列化上下文引用鏈,記錄對象層次關系
public void setContext(SerialContext parent, Object object, Object fieldName, int features, int fieldFeatures) {
if (out.disableCircularReferenceDetect) {
return;
}
//構建當前上下文到parent上下文引用鏈
this.context = new SerialContext(parent, object, fieldName, features, fieldFeatures);
if (references == null) {
references = new IdentityHashMap<Object, SerialContext>();
}
this.references.put(object, context);
}
//檢查對象是否已被序列化,防止重復序列化
public boolean containsReference(Object value) {
if (references == null) {
return false;
}
SerialContext refContext = references.get(value);
if (refContext == null) {
return false;
}
if (value == Collections.emptyMap()) {
return false;
}
Object fieldName = refContext.fieldName;
return fieldName == null || fieldName instanceof Integer || fieldName instanceof String;
}
//清理上下文,將當前序列化上下文指向父親節點
public void popContext() {
if (context != null) {
this.context = this.context.parent;
}
}字段值轉換與序列化
FieldSerializer.writeValue()核心邏輯
FieldSerializer 的writeValue方法實現了字段值的序列化操作:
public void writeValue(JSONSerializer serializer, Object propertyValue) throws Exception {
// 運行時類型識別
Class<?> runtimeFieldClass = propertyValue != null ?
propertyValue.getClass() : this.fieldInfo.fieldClass;
// 查找屬性類型對應的序列化器
ObjectSerializer fieldSerializer = serializer.getObjectWriter(runtimeFieldClass);
// 處理特殊格式和注解
if (format != null && !(fieldSerializer instanceof DoubleSerializer)) {
serializer.writeWithFormat(propertyValue, format);
return;
}
// 委托給具體序列化器處理
fieldSerializer.write(serializer, propertyValue, fieldInfo.name,
fieldInfo.fieldType, fieldFeatures);
}不同類型的序列化策略
基礎類型序列化 :
- 直接調用SerializeWriter的對應方法(writeInt、writeString等)
復雜對象序列化 :
- 遞歸調用JSONSerializer.write()方法
- 維護序列化上下文和引用關系
- 應用過濾器和特性配置
ASM定制化序列化器加速,下文會進行詳細講解。
- 為序列化的類動態生成定制化的序列化器,避免反射調用開銷
JSON字符串構建
SerializeWriter.java采用線程本地緩沖機制,提供高效的字符串構建:
//用于存儲存JSON字符串
private final static ThreadLocal<char[]> bufLocal = new ThreadLocal<char[]>();
//將字符串轉換為UTF-8字節數組
private final static ThreadLocal<byte[]> bytesBufLocal = new ThreadLocal<byte[]>();- 字符緩沖區 : 線程本地char[]數組減少內存分配,避免頻繁創建臨時數組對象。
- 動態擴容 : 根據內容長度自動調整緩沖區大小。
bufLocal初始化創建2048字符的緩沖區,回收階段當緩沖區大小不超過 BUFFER_THRESHOLD (128KB)時,將其放回ThreadLocal緩存,超過閾值的大緩沖區不緩存,避免內存占用過大。
bytesBufLocal專門用于UTF-8編碼轉換過程,初始緩沖區大小:8KB(1024 * 8),根據字符數量估算所需字節數(字符數 × 3),只有不超過 BUFFER_THRESHOLD 的緩沖區才會被緩存。
序列化小結
Fastjson通過JSON.toJSONString()門面API調用JSONSerializer控制器,利用ASM字節碼生成的高性能序列化器或反射機制遍歷Java對象字段,配合SerializeWriter將字段名和值逐步寫入緩沖區構建JSON字符串。
反序列化流程
雖然“序列化”與“反序列化”在概念上是對偶的(Serialize ? Deserialize),但在實現層面并不嚴格對偶,反序列化實現明顯比序列化復雜。核心步驟包括:反序列化器查找→ 反序列流程控制→詞法分析器(Tokenizer) → 安全檢查→反射/ASM 字段填充等,下圖為處理時序圖:
圖片
反序列化入口與反序列化器選擇
反序列化從 JSON.java的parseObject方法開始:
// JSON.java - 反序列化入口
public static <T> T parseObject(String text, Class<T> clazz, int features) {
if (text == null) {
return null;
}
DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance(), features);
T value = (T) parser.parseObject(clazz);
parser.handleResovleTask(value);
parser.close();
return value;
}查找反序列化器
在 DefaultJSONParser.java 中選擇合適的反序列化器:
// DefaultJSONParser.java - 反序列化器選擇
public <T> T parseObject(Type type, Object fieldName) {
int token = lexer.token();
if (token == JSONToken.NULL) {
lexer.nextToken();
return (T) TypeUtils.optionalEmpty(type);
}
//從緩存中查找反序列化器
ObjectDeserializer deserializer = config.getDeserializer(type);
try {
if (deserializer.getClass() == JavaBeanDeserializer.class) {
return (T) ((JavaBeanDeserializer) deserializer).deserialze(this, type, fieldName, 0);
} else {
return (T) deserializer.deserialze(this, type, fieldName);
}
} catch (JSONException e) {
throw e;
} catch (Throwable e) {
throw new JSONException(e.getMessage(), e);
}
}ParserConfig.java 負責獲取對應類型的反序列化器:
// ParserConfig.java - 反序列化器獲取
public ObjectDeserializer getDeserializer(Type type) {
ObjectDeserializer deserializer = this.deserializers.get(type);
if (deserializer != null) {
return deserializer;
}
//通過Class查找
if (type instanceof Class<?>) {
return getDeserializer((Class<?>) type, type);
}
//通過泛型參數查找
if (type instanceof ParameterizedType) {
Type rawType = ((ParameterizedType) type).getRawType();
if (rawType instanceof Class<?>) {
return getDeserializer((Class<?>) rawType, type);
} else {
return getDeserializer(rawType);
}
}
return JavaObjectDeserializer.instance;
}反序列化控制流程
JavaBeanDeserializer.java 的deserialze實現了反序列化主要處理流程。
// JavaBeanDeserializer.java - 類型識別與字段匹配
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName, int features, int[] setFlags) {
// 1.特殊類型快速處理
if (type == JSON.class || type == JSONObject.class) {
return (T) parser.parse();
}
//2.初始化核心組件
final JSONLexer lexer = parser.lexer;
//3.反序列化上下文管理
ParseContext context = parser.getContext();
if (object != null && context != null) {
context = context.parent;
}
ParseContext childContext = null;
//保存解析后字段值
Map<String, Object> fieldValues = null;
// JSON關鍵字分支預處理
if (token == JSONToken.RBRACE) {
lexer.nextToken(JSONToken.COMMA);
if (object == null) {
object = createInstance(parser, type);
}
return (T) object;
}
//處理其他JSON關鍵字
...
//4.字段解析主循環
for (int fieldIndex = 0, notMatchCount = 0;; fieldIndex++) {
boolean customDeserializer = false;
//這是一個性能優化的設計,通過預排序和索引訪問來提高字段匹配的效率,
//通常情況下JSON串按字段定義順序排列,因此能快速命中
if (fieldIndex < sortedFieldDeserializers.length && notMatchCount < 16) {
fieldDeserializer = sortedFieldDeserializers[fieldIndex];
fieldInfo = fieldDeserializer.fieldInfo;
fieldClass = fieldInfo.fieldClass;
fieldAnnotation = fieldInfo.getAnnotation();
if (fieldAnnotation != null && fieldDeserializer instanceof DefaultFieldDeserializer) {
customDeserializer = ((DefaultFieldDeserializer) fieldDeserializer).customDeserilizer;
}
}
Object fieldValue = null;
if (fieldDeserializer != null) {
char[] name_chars = fieldInfo.name_chars;
//指定了自定義發序列化器,后續使用自定義序列化器處理
if (customDeserializer && lexer.matchField(name_chars)) {
matchField = true;
// 基本類型快速路徑匹配
} else if (fieldClass == int.class || fieldClass == Integer.class) {
//詞法分析,解析int值
int intVal = lexer.scanFieldInt(name_chars);
if (intVal == 0 && lexer.matchStat == JSONLexer.VALUE_NULL) {
fieldValue = null;
} else {
fieldValue = intVal;
}
if (lexer.matchStat > 0) {
matchField = true;
valueParsed = true;
} else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {
//增加計算,記錄未命中次數以調整匹配策略
notMatchCount++;
continue;
}
} else if(...){
//省略其他基礎類型處理
}
}
// 快速匹配失敗,動態掃描字段名,通過符號表優化:返回的字符串可能是符號表中的緩存實例
if (!matchField) {
key = lexer.scanSymbol(parser.symbolTable);
// $ref 引用處理
if ("$ref" == key && context != null) {
handleReferenceResolution(lexer, parser, context)
}
// @type 類型處理
if ((typeKey != null && typeKey.equals(key))
|| JSON.DEFAULT_TYPE_KEY == key) {
//AutoType安全檢查
config.checkAutoType(typeName, expectClass, lexer.getFeatures());
handleTypeNameResolution(lexer, parser, config, beanInfo, type, fieldName);
}
}
}
// 5.如果對象為空,則創建對象實例
if (object == null && fieldInfo == null) {
object = createInstance(parser, type);
if (object == null) {
return null;
}
}
//6. 字段值設置
for (Map.Entry<String, Object> entry : fieldValues.entrySet()) {
FieldDeserializer fieldDeserializer = getFieldDeserializer(entry.getKey());
if (fieldDeserializer != null) {
fieldDeserializer.setValue(object, entry.getValue());
}
}
return (T) object;
}字符串解析階段(詞法分析)
JSONLexerBase內部維護詞法解析狀態機,實現詞法分析核心邏輯,下面展示了Integer值類型處理源碼:
public int scanFieldInt(char[] fieldName) {
matchStat = UNKNOWN;
// 1. 字段名匹配階段
if (!charArrayCompare(fieldName)) {
matchStat = NOT_MATCH_NAME;
return 0;
}
int offset = fieldName.length;
char chLocal = charAt(bp + (offset++));
// 2. 負號處理
final boolean negative = chLocal == '-';
if (negative) {
chLocal = charAt(bp + (offset++));
}
// 3. 數字解析核心算法
int value;
if (chLocal >= '0' && chLocal <= '9') {
value = chLocal - '0';
for (;;) {
chLocal = charAt(bp + (offset++));
if (chLocal >= '0' && chLocal <= '9') {
value = value * 10 + (chLocal - '0');// 十進制累加
} else if (chLocal == '.') {
matchStat = NOT_MATCH; // 拒絕浮點數
return 0;
} else {
break;
}
}
// 4. 溢出檢測
if (value < 0 //
|| offset > 11 + 3 + fieldName.length) {
if (value != Integer.MIN_VALUE //
|| offset != 17 //
|| !negative) {
matchStat = NOT_MATCH;
return 0;
}
}
} else {
matchStat = NOT_MATCH;
return 0;
}
// 5. JSON 結束符處理
if (chLocal == ',') {
bp += offset;
this.ch = this.charAt(bp);
matchStat = VALUE;
token = JSONToken.COMMA;
return negative ? -value : value;
}
if (chLocal == '}') {
// ... 處理對象結束和嵌套結構
chLocal = charAt(bp + (offset++));
if (chLocal == ',') {
token = JSONToken.COMMA;
bp += offset;
this.ch = this.charAt(bp);
} else if (chLocal == ']') {
token = JSONToken.RBRACKET;
bp += offset;
this.ch = this.charAt(bp);
} else if (chLocal == '}') {
token = JSONToken.RBRACE;
bp += offset;
this.ch = this.charAt(bp);
} else if (chLocal == EOI) {
token = JSONToken.EOF;
bp += (offset - 1);
ch = EOI;
} else {
matchStat = NOT_MATCH;
return 0;
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return 0;
}
return negative ? -value : value;
}類型安全檢查(AutoType檢查)
ParserConfig.java 中的checkAutoType方法對反序列化類型做黑白名單檢查。
// ParserConfig.java - AutoType安全檢查
public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features) {
if (typeName == null) {
return null;
}
if (typeName.length() >= 192 || typeName.length() < 3) {
throw new JSONException("autoType is not support. " + typeName);
}
String className = typeName.replace('$', '.');
Class<?> clazz = null;
final long BASIC = 0xcbf29ce484222325L;
final long PRIME = 0x100000001b3L;
final long h1 = (BASIC ^ className.charAt(0)) * PRIME;
// hash code編碼匹配性能優化
if (h1 == 0xaf64164c86024f1aL) {
throw new JSONException("autoType is not support. " + typeName);
}
if ((h1 ^ className.charAt(className.length() - 1)) * PRIME == 0x9198507b5af98f0L) {
throw new JSONException("autoType is not support. " + typeName);
}
final long h3 = (((((BASIC ^ className.charAt(0))
* PRIME)
^ className.charAt(1))
* PRIME)
^ className.charAt(2))
* PRIME;
if (autoTypeSupport || expectClass != null) {
long hash = h3;
for (int i = 3; i < className.length(); ++i) {
hash ^= className.charAt(i);
hash *= PRIME;
if (Arrays.binarySearch(denyHashCodes, hash) >= 0 && TypeUtils.getClassFromMapping(typeName) == null) {
throw new JSONException("autoType is not support. " + typeName);
}
if (Arrays.binarySearch(acceptHashCodes, hash) >= 0) {
clazz = TypeUtils.loadClass(typeName, defaultClassLoader, false);
if (clazz != null) {
return clazz;
}
}
}
}
// ... 更多安全檢查邏輯
return clazz;
}對象實例化過程
JavaBeanDeserializer.java中的createInstance方法創建對象實例:
// JavaBeanDeserializer.java - 對象實例化
protected Object createInstance(DefaultJSONParser parser, Type type) {
if (type instanceof Class) {
if (clazz.isInterface()) {
// 接口類型使用Java反射創建實例
Class<?> clazz = (Class<?>) type;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
final JSONObject obj = new JSONObject();
Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { clazz }, obj);
return proxy;
}
}
if (beanInfo.defaultConstructor == null && beanInfo.factoryMethod == null) {
return null;
}
Object object;
try {
//通過構造器創建實例
Constructor<?> constructor = beanInfo.defaultConstructor;
if (beanInfo.defaultConstructorParameterSize == 0) {
object = constructor.newInstance();
} else {
ParseContext context = parser.getContext();
if (context == null || context.object == null) {
throw new JSONException("can't create non-static inner class instance.");
}
final Class<?> enclosingClass = constructor.getDeclaringClass().getEnclosingClass();
object = constructor.newInstance(context.object);
}
} catch (JSONException e) {
throw e;
} catch (Exception e) {
throw new JSONException("create instance error, class " + clazz.getName(), e);
}
return object;
}FieldDeserializer.java中的setValue方法通過反射實現字段設置:
// FieldDeserializer.java - 屬性賦值的核心實現
public void setValue(Object object, Object value) {
if (value == null && fieldInfo.fieldClass.isPrimitive()) {
return;
} else if (fieldInfo.fieldClass == String.class
&& fieldInfo.format != null
&& fieldInfo.format.equals("trim")) {
value = ((String) value).trim();
}
try {
Method method = fieldInfo.method;
if (method != null) {
if (fieldInfo.getOnly) {
// 處理只讀屬性的特殊情況
if (fieldInfo.fieldClass == AtomicInteger.class) {
AtomicInteger atomic = (AtomicInteger) method.invoke(object);
if (atomic != null) {
atomic.set(((AtomicInteger) value).get());
}
} else if (Map.class.isAssignableFrom(method.getReturnType())) {
Map map = (Map) method.invoke(object);
if (map != null) {
map.putAll((Map) value);
}
} else {
Collection collection = (Collection) method.invoke(object);
if (collection != null && value != null) {
collection.clear();
collection.addAll((Collection) value);
}
}
} else {
// 通過setter方法賦值
method.invoke(object, value);
}
} else {
// 通過字段直接賦值
final Field field = fieldInfo.field;
if (field != null) {
field.set(object, value);
}
}
} catch (Exception e) {
throw new JSONException("set property error, " + clazz.getName() + "#" + fieldInfo.name, e);
}
}反序列化小結
Fastjson通過JSON.parseObject()門面API調用DefaultJSONParser控制器,利用JSONLexer進行詞法分析解析JSON字符串,經過AutoType安全檢查后使用ASM字節碼生成動態反序列化器或反射機制創建Java對象實例并逐字段賦值。
五、特性講解
ASM性能優化
ASM 是 fastjson 類似于 JIT,在運行時把「反射調用」翻譯成「直接字段訪問 + 方法調用」的字節碼,從而把序列化/反序列化性能提升 20% 以上,當然隨著JVM對反射性能的優化性能差正在逐漸被縮小。下圖是作者使用工具類讀取的動態序列化/反序列化器源碼片段。
圖片
圖片
圖片
圖片
AutoType機制
AutoType是 fastjson 的“動態多態還原”方案:
序列化時把具體子類名字寫進 "@type",反序列化時先加載類 → 再調 setter → 完成還原。
速度上“指針引用”即可定位序列化器,功能上靠 @type 字段把被擦除的泛型/接口/父類重新映射回具體實現。
在未開啟AutoType機制情況下,在將store對象序列化成JSON串后,再反序列化為對象時由于字段的類型為接口無法轉換成具體的Dog類型示例;開啟AutoType機制后,序列化時將類型一并寫入到JSON串內,后續進行反序列化時可以根據這個類型還原成具體的類型實例。
interface Animal {}
class Dog implements Animal {
private String name;
private double weight;
//省略getter,setter
}
class PetStore {
private Animal animal;
}
public static void main(String[] args) {
Animal dog = new Dog("dodi", 12);
PetStore store = new PetStore(dog);
String jsonString = JSON.toJSONString(store);
PetStore petStore = JSON.parseObject(jsonString, PetStore.class);
Dog parsedDog = (Dog) petStore.getAnimal();
}
圖片
圖片
public static void main(String[] args) {
Animal dog = new Dog("dodi", 12);
PetStore store = new PetStore(dog);
String jsonString = JSON.toJSONString(store, SerializerFeature.WriteClassName);
PetStore petStore = JSON.parseObject(jsonString, PetStore.class);
Dog parsedDog = (Dog) petStore.getAnimal();
}
圖片
AutoType 讓 fastjson 在反序列化時根據 @type 字段動態加載任意類,這一“便利”卻成為攻擊者遠程代碼執行的快捷通道:通過把JdbcRowSetImpl等 JNDI 敏感類寫進 JSON,服務端在調用 setter 的瞬間就會向外部 LDAP/RMI 服務器拉取惡意字節碼,完成 RCE;而官方長期依賴“黑名單”堵漏,導致 1.2.25→1.2.80 出現 L 描述符、Throwable 二次反序列化、內部類等連續繞過,形成“補丁-繞過-再補丁”的貓鼠游戲, 雖然在1.2.68 引入 safeMode 但為了兼容性需要使用者手動開啟 ,而且實現也不夠健壯,開啟safeMode仍有利用代碼漏洞繞過檢查風險,后續版本對safeMode加固并對已知安全漏洞清零,直到最新1.2.83版本安全問題也不能說徹底解決。
流式解析
Fastjson 提供一套 Streaming API,核心類JSONReader /JSONWriter,行業內慣稱「流式解析」或「增量解析」,主要用于處理JSON大文件解析。技術上流式解析采用“拉模式(pull parsing)”,底層維護 8 KB 滑動緩沖,詞法分析器(Tokenizer)把字節流切成 token 流,語法狀態機根據 token 類型驅動反序列化器(ObjectReader)即時產出 Java 對象,對象一旦交付給用戶代碼處理后,內部引用立即釋放。這種方式內存中不會保存所有對象,對象處理完即被丟棄,因此可以處理數據量遠大于內存的數據,而不會出現OOM。下面是使用流式解析的示例代碼:
// 依賴:com.alibaba:fastjson:1.2.83
try (JSONReader reader = new JSONReader(
new InputStreamReader(
new FileInputStream("huge-array.json"), StandardCharsets.UTF_8))) {
reader.startArray(); // 告訴解析器:根節點是 []
while (reader.hasNext()) { // 拉取下一條
Order order = reader.readObject(Order.class); // 瞬時對象
processOrder(order);//業務處理
orderRepository.save(order); // 立即落盤,內存即可回收
}
reader.endArray();
}六、總結
Fastjson核心特性在于高速序列化/反序列化,利用ASM在運行時生成字節碼動態創建解析器,減少反射;AutoType字段支持多態,卻帶來反序列化RCE風險,建議關閉AutoType,開啟safeMode。選型建議:在選擇JSON序列化框架時對于非極端性能要求推薦Jackson,或者使用Fastjson2,其改用LambdaMetafactory替換ASM,性能再提升30%,默認關閉AutoType安全性有保證。
參考資料:
- FastJson 反序列化漏洞原理分析(https://www.cnblogs.com/Only-xiaoxiao/p/17213248.html)
- 序列化與反序列化——FastJSON、Jackson、Gson性能測試(https://zhuanlan.zhihu.com/p/529342385)
- FASTJSON 2 Autotype機制介紹(https://alibaba.github.io/fastjson2/autotype_cn.html)






















