精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從 JSON 字符串到 Java 對象:Fastjson 1.2.83 全程解析

開發 前端
Fastjson核心特性在于高速序列化/反序列化,利用ASM在運行時生成字節碼動態創建解析器,減少反射;AutoType字段支持多態,卻帶來反序列化RCE風險,建議關閉AutoType,開啟safeMode。

一、概述

二、核心模塊架構

三、項目結構

    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)
責任編輯:武曉燕 來源: 得物技術
相關推薦

2013-07-23 06:39:49

Json字符串到JsoAndroid開發學習Json萬能解析器

2015-07-02 10:37:32

C#Json字符串類代碼

2010-01-07 16:55:06

JSON字符串

2010-07-14 12:39:30

Prel字符串

2023-05-05 07:49:07

GolangJSON格式

2020-07-06 14:16:22

Fastjson漏洞開源

2009-03-23 14:14:33

JSONAJAXJavaScript

2015-11-16 10:24:45

Java常量池字符串

2015-03-19 15:04:06

2015-10-27 09:41:16

Javaintern

2009-06-23 14:13:00

Java字符串

2010-01-06 16:33:04

JSON對象標記

2010-03-22 17:53:50

Python字符Python字符串

2009-11-25 09:13:41

PHP數組轉字符串PHP字符串轉數組

2021-09-17 14:13:28

JavaScript編程字符串

2009-11-26 16:26:32

PHP字符串mbstr

2020-11-13 08:14:28

JavaScript

2023-06-21 00:10:17

JSONWeb服務器JavaScript

2009-10-13 16:09:27

.NET字符串解析

2009-09-02 15:53:27

C#判斷字符串應用
點贊
收藏

51CTO技術棧公眾號

亚洲欧美视频一区二区三区| 亚洲福利合集| 中文字幕色av一区二区三区| 亚洲自拍偷拍网址| 91精品国产乱码在线观看| 视频一区欧美| 91精品国产91综合久久蜜臀| 青青草国产精品视频| 国产尤物视频在线| 国产成人av福利| 国产精品第三页| 国产一级久久久| 精品美女在线视频| 精品盗摄一区二区三区| 国产精品igao| 国产传媒在线观看| 亚洲天堂精品视频| 日本精品一区| 日本韩国免费观看| 热久久一区二区| 高清亚洲成在人网站天堂| 日韩不卡av在线| 日韩成人一级| 日韩精品一区二区三区老鸭窝| 国产成人精品无码播放| 黄色动漫在线观看| 日本一区二区久久| 久久久久高清| 蜜桃91麻豆精品一二三区| 男人的天堂久久精品| 26uuu日韩精品一区二区| 外国一级黄色片| 欧美综合一区| 亚洲欧美日韩中文在线| 国产一线在线观看| 精品国产亚洲一区二区在线观看 | 亚洲精品在线免费看| 刘亦菲久久免费一区二区| 国产呦萝稀缺另类资源| 国产精品嫩草视频| 依依成人综合网| 亚洲国产免费| 欧美精品激情在线观看| 性色av无码久久一区二区三区| 欧美在线电影| 尤物九九久久国产精品的分类 | 高清欧美性猛交xxxx| 神马久久精品综合| 午夜片欧美伦| 久久在线视频在线| 日韩精品一区二区亚洲av性色| 不卡在线一区| 中文字幕综合在线| 欧美国产视频在线| 久久久久久国产精品mv| 欧美自拍偷拍第一页| 国产精品12区| 99在线国产| 国产极品999| 国产高清成人在线| 爱情岛论坛亚洲入口| 成人av免费播放| 国产不卡在线一区| 国产乱人伦精品一区二区| 高清国产mv在线观看| 成人国产精品免费观看| 国产精品一国产精品最新章节| 日韩最新av在线| 91视频在线网站| 精品国产aⅴ| 最近更新的2019中文字幕| 欧美福利第一页| 色综合天天爱| 久99久在线视频| 国产一级视频在线| 亚洲一区黄色| 国产精品成人v| 国产影视一区二区| 国产成人亚洲精品青草天美| 国产精品久久7| 婷婷亚洲一区二区三区| 久久久久久久久免费| 先锋影音亚洲资源| 伊人电影在线观看| 天天综合日日夜夜精品| 少妇高清精品毛片在线视频| 日本美女久久| 日韩欧美亚洲国产精品字幕久久久| 男人女人拔萝卜视频| 清纯唯美亚洲经典中文字幕| 亚洲美女又黄又爽在线观看| 国产一二三av| 国产精品啊啊啊| 人体精品一二三区| 国产理论片在线观看| www.日韩大片| 亚洲欧洲精品一区二区三区波多野1战4 | 韩日成人在线| 日本欧美爱爱爱| 国产剧情精品在线| 久久综合色播五月| 男女啪啪的视频| 深夜成人在线| 69堂国产成人免费视频| bl动漫在线观看| 久久在线电影| 69久久夜色精品国产69乱青草| 自拍偷拍色综合| 不卡一二三区首页| 天堂一区二区三区| av毛片午夜不卡高**水| 欧美日韩一级视频| 中文字幕人妻一区二区三区| 不卡日本视频| 97视频在线观看成人| 在线观看免费观看在线| 成人av网站大全| 正在播放亚洲| 亚洲伊人av| 欧美久久久久久久久| 国产精品一级无码| 色天天综合网| 欧洲成人在线观看| 亚洲老妇色熟女老太| 国产精品私人影院| 男人操女人免费软件| 久久综合偷偷噜噜噜色| 在线观看亚洲区| 日本一区二区欧美| 国产麻豆成人传媒免费观看| 欧美性xxxx69| 黄色在线免费观看网站| 日韩丝袜美女视频| 五月综合色婷婷| 日韩精品欧美精品| 久久精品人成| av男人的天堂在线观看| 日韩欧美第一区| 日本 欧美 国产| 日韩中文字幕亚洲一区二区va在线 | 欧美高清中文字幕| 999色成人| 丝袜情趣国产精品| 中文字幕永久在线观看| 国产亚洲欧洲一区高清在线观看| 好吊妞无缓冲视频观看| 91久久精品无嫩草影院| 欧美成人精品一区| 国产黄色一级大片| 亚洲精品午夜久久久| 中文字幕66页| 99精品一区| 国产精品女人网站| jizz视频在线观看| 欧美性受xxxx| 久久久久麻豆v国产| 蜜桃视频免费观看一区| 日韩电影大全在线观看| 成人免费看黄| 亚洲天堂影视av| 波多野结衣视频观看| 久久久精品2019中文字幕之3| 免费看国产曰批40分钟| 精品少妇3p| 欧美一区二区三区免费观看| 婷婷婷国产在线视频| 欧美性猛xxx| 日本xxxxxxxxx18| 日本视频中文字幕一区二区三区| 日韩国产高清一区| 欧美视频精品| 九九热精品视频| 人妻中文字幕一区| 色综合久久综合网| 日本污视频网站| 国产酒店精品激情| 日韩欧美不卡在线| 五月天亚洲一区| 国产成人精品亚洲精品| a天堂中文在线88| 欧美久久久久久久久| 久久免费播放视频| 91年精品国产| 中文字幕第100页| 亚洲色图网站| 精品视频第一区| 国产第一亚洲| 欧美日韩国产成人在线观看| 午夜av免费在线观看| 在线观看亚洲精品| 欧美成人精品欧美一级私黄| 91日韩在线专区| 视频在线观看免费高清| 国产精品激情| 日韩hmxxxx| 亚洲成人五区| 国产精品第一第二| 丰满诱人av在线播放| 国产一区二区黑人欧美xxxx| 国产成人精品白浆久久69| 婷婷国产在线综合| 欧美第一页在线观看| 99精品国产一区二区三区不卡| 在线免费视频a| 影音先锋一区| 一区二区欧美日韩| 日韩欧美美女在线观看| 国产日韩换脸av一区在线观看| av毛片在线看| 一区二区三区四区在线观看视频 | 日韩精品免费在线视频观看| 在线观看黄色国产| 无吗不卡中文字幕| 91日韩中文字幕| 国产亚洲一区字幕| 性鲍视频在线观看| 日韩av一区二| 欧美综合在线播放| **女人18毛片一区二区| 欧美日韩喷水| 露出调教综合另类| 亚洲在线第一页| 成人亚洲免费| 欧美在线视频免费播放| 国产精品蜜臀| 美女av一区二区| 日本三级在线视频| 亚洲欧美日韩天堂一区二区| 午夜小视频免费| 亚洲精品在线免费播放| 国产农村老头老太视频| 欧美亚洲免费在线一区| 久久精品国产成人av| 亚洲自拍另类综合| 国产av 一区二区三区| 国产精品久久久久久久岛一牛影视| 韩国无码一区二区三区精品| 成人晚上爱看视频| 中文字幕无码毛片免费看| 久久精品国产成人一区二区三区 | 日韩理论片久久| 丰满人妻妇伦又伦精品国产| 91精品一区二区三区久久久久久 | 涩涩视频在线播放| 高清一区二区三区四区五区| 91高清在线观看视频| 麻豆一区二区在线观看| 日本中文字幕在线播放| 深夜福利亚洲导航| 99精品老司机免费视频| 伊人伊成久久人综合网小说 | 欧美巨猛xxxx猛交黑人97人| 99免在线观看免费视频高清| 自拍偷拍亚洲一区| 五月婷婷在线观看| 久久精品久久久久久| 美女免费久久| 不卡av电影院| 7777kkk亚洲综合欧美网站| 久久久久久美女| 3344国产永久在线观看视频| 国产+人+亚洲| 日韩理论视频| 国产成人精品免高潮费视频| 成人免费av电影| 国产精品视频久久久| 久久免费影院| 91亚洲va在线va天堂va国| 欧州一区二区三区| 成人高清在线观看| 日韩成人动漫在线观看| 日本不卡久久| 国产高清久久| 成人高清dvd| a91a精品视频在线观看| 日韩 欧美 高清| 精品一区二区三区日韩| 伊人精品视频在线观看| 成人免费黄色在线| 国产精品亚洲无码| 国产精品久久久久久久蜜臀| 伊人在线视频观看| 亚洲国产精品一区二区久久 | 丁香花五月婷婷| 亚洲特黄一级片| 亚洲精品午夜久久久久久久| 一本大道综合伊人精品热热| 中文字幕欧美人妻精品一区蜜臀| 3atv一区二区三区| 亚洲av成人无码网天堂| 在线电影欧美日韩一区二区私密| 超碰公开在线| 日本高清久久天堂| aa亚洲一区一区三区| 国产一区二区在线网站| 欧美综合在线视频观看| 国产在线观看欧美| 日韩精品电影一区亚洲| 中文字幕在线播放一区二区| 久久精品在线观看| 久久久国产精品人人片| 欧洲国产伦久久久久久久| 国产精品久久无码一三区| 日韩av最新在线观看| 在线免费看a| 2025国产精品视频| 欧美经典一区| 亚洲精品一区二区三区四区五区| 影音先锋中文字幕一区| 亚洲天堂网2018| 2024国产精品| 久久99久久98精品免观看软件| 色吊一区二区三区| 人妻妺妺窝人体色www聚色窝| 在线观看成人黄色| 深夜av在线| 99久久综合狠狠综合久久止| 精品美女在线视频| 欧美丰满熟妇bbbbbb百度| 国产资源在线一区| 国产成人免费观看网站| 欧美日韩国产影院| 午夜精品久久久久久久99| 有码中文亚洲精品| 中文在线а√在线8| 2022国产精品| 先锋资源久久| 视色视频在线观看| 国产免费久久精品| 国产欧美一区二区三区在线看蜜臂| 日韩一区二区不卡| 日韩免费啪啪| 国产精品三级久久久久久电影| 日韩mv欧美mv国产网站| 黄色大片在线免费看| 丁香激情综合国产| jizz亚洲少妇| 91精品国产综合久久香蕉的特点| 大地资源中文在线观看免费版| 欧美一级视频免费在线观看| 国产精品一线| 久久久久久久久久网| 粉嫩av一区二区三区粉嫩| 九九热只有精品| 日韩欧美中文字幕一区| 国产黄色在线免费观看| 成人免费看片视频| 亚欧美无遮挡hd高清在线视频| 在线观看av网页| 亚洲欧洲日韩综合一区二区| 伊人免费在线观看高清版| 中文字幕无线精品亚洲乱码一区 | 国模精品视频| 激情视频在线观看一区二区三区| 亚洲激情亚洲| 成人无码www在线看免费| 狠狠躁18三区二区一区| 色网站在线免费观看| 欧美专区第一页| 国内成人自拍| jizz大全欧美jizzcom| 国产精品家庭影院| 国产成人精品毛片| 久久久久久久久久久国产| 精品久久ai| 久草综合在线观看| 国产精品久久看| 国产chinasex对白videos麻豆| 欧美激情中文网| 欧美三级午夜理伦三级小说| 精品人妻一区二区三区四区在线 | 一区二区三区在线播放视频| 欧美一区二区视频免费观看| 青青草原av在线| 麻豆成人av| 蜜臀av国产精品久久久久| 国精产品一区一区二区三区mba | 2025中文字幕| 午夜一区二区三区视频| 黄色毛片在线观看| 国产日本欧美一区二区三区| 国产一区亚洲| 中文字幕免费看| 欧美精品99久久久**| 97天天综合网| 亚洲国产精品www| 国产成人a级片| 免费av中文字幕| 欧美成人四级hd版| 亚洲精品无吗| 免费网站在线观看黄| 午夜欧美2019年伦理| 东热在线免费视频| 成人av资源网| 日本中文字幕一区二区视频| 色婷婷在线视频观看| 国产视频一区在线| 国产精品99久久免费| 黄色免费观看视频网站| 亚洲免费资源在线播放|