精品欧美一区二区三区在线观看 _久久久久国色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夜夜揉人人捏人人添红杏| 亚洲精品午夜国产va久久成人| 欧美色女视频| 精品久久久久香蕉网| 国产天堂在线播放| 色a资源在线| 欧美伦理在线视频| 日韩欧美国产综合一区| 久久精品视频91| 狂野欧美性猛交xxxxx视频| 久久蜜桃一区二区| 成人资源av| 国产又大又粗又长| 噜噜噜91成人网| 欧美黑人视频一区| 天天爽天天爽天天爽| 香蕉精品久久| 亚洲福利视频二区| 日韩在线一区视频| 欧美黄色三级| 国产亚洲自拍一区| 粉嫩av四季av绯色av第一区| 中文字幕网址在线| 亚洲永久免费| 久久久影视精品| 国产在线观看免费视频软件| 国产欧美日韩视频在线| 亚洲经典中文字幕| 99riav国产精品视频| 欧美系列精品| 欧美日韩一区二区三区免费看| 男人操女人逼免费视频| 国产精品国产高清国产| 国产成人久久精品77777最新版本| 久久国产精品久久久| 熟女俱乐部一区二区| 特黄特色欧美大片| 亚洲精品一区二区三区四区高清| 亚洲制服在线观看| 国产精品久久久久久久久久久久久久久| 色8久久人人97超碰香蕉987| 97国产精东麻豆人妻电影 | 美女av免费观看| 性欧美18一19性猛交| 国精产品一区一区三区mba视频| 国产精品久久久久久久久男 | 欧美黑人xxxxx| 午夜影院在线视频| 91视频国产观看| 国产精品久久二区| 丰满少妇xoxoxo视频| 久久视频精品| 亚洲国产精品一区二区三区| 97中文字幕在线观看| 一区二区在线视频观看| 欧美不卡一区二区三区| 国产精品入口麻豆| 噜噜噜狠狠夜夜躁精品仙踪林| 亚洲国产天堂久久国产91| 欧美肉大捧一进一出免费视频| **欧美日韩在线观看| 在线欧美日韩国产| a级黄色片免费| 中文字幕中文字幕在线中高清免费版| 99视频一区二区三区| 国产精品美女xx| 五月婷婷在线观看视频| 久久精品人人做人人爽人人| 一区二区精品在线观看| 在线黄色网页| 一本到不卡精品视频在线观看| 手机看片福利盒子久久| www.欧美| 亚洲精品福利视频| 亚洲黄色网址大全| 美女视频亚洲色图| 亚洲色图第三页| 精品国产精品国产精品| 亚洲韩日在线| 国产精品网址在线| 亚洲大尺度网站| 久久久久久9999| 欧美日韩亚洲国产成人| 国产精品一二三产区| 欧美午夜精品理论片a级按摩| 亚洲天堂伊人网| 小说区图片区色综合区| 精品激情国产视频| 国产精品美女久久久久av爽| 麻豆视频观看网址久久| 国内一区二区三区在线视频| fc2在线中文字幕| 亚洲电影在线播放| www.超碰97.com| 无码日韩精品一区二区免费| 久久精品国产综合| 国产一级免费视频| 国产成人精品亚洲777人妖| 奇米影视首页 狠狠色丁香婷婷久久综合 | 日本黄色片一级片| 日本欧美韩国| 亚洲成人久久久| 午夜剧场免费在线观看| 久热综合在线亚洲精品| 91产国在线观看动作片喷水| 在线免费看av片| 91麻豆国产在线观看| 成人污网站在线观看| 日本精品在线一区| 亚洲国产中文字幕在线观看| 粉嫩av性色av蜜臀av网站| 视频一区二区三区中文字幕| 国产在线一区二| 香蕉久久aⅴ一区二区三区| 欧美色老头old∨ideo| 黄色在线观看av| 亚洲欧洲视频| 国产91一区二区三区| 国产写真视频在线观看| 欧美性大战久久久久久久蜜臀| 粉嫩av懂色av蜜臀av分享| 亚洲在线久久| 91免费综合在线| 日本在线人成| 欧美精品色一区二区三区| 中国女人特级毛片| 99久久夜色精品国产亚洲1000部| 日韩av快播网址| 五月婷婷综合久久| 亚洲一区二区三区四区在线 | 久久网福利资源网站| 国产免费a视频| 成人一区在线观看| 国产精品第二页| 日韩三级电影网| 午夜精品久久久久久久| 北京富婆泄欲对白| 亚洲精选国产| 久久亚洲国产精品日日av夜夜| 国产精选在线| 日韩av在线看| 伦av综合一区| 国产日韩精品一区| 日本久久久久久久久久久久| 日韩视频网站在线观看| 日韩电影免费在线观看中文字幕 | 国内自拍一区| 国产69久久精品成人| 天天操天天干天天操| 亚洲成人一二三| 中文字幕在线永久| 性欧美videos另类喷潮| 麻豆成人小视频| 日韩av超清在线观看| 在线观看国产成人av片| 久久精品波多野结衣| 国产不卡视频在线播放| 中文字幕无码精品亚洲资源网久久| 国产精品tv| 日本道色综合久久影院| 福利在线午夜| 欧美日韩精品免费| 丰满少妇高潮久久三区| 成人黄色综合网站| 国产超级av在线| 日韩精品免费| 57pao成人国产永久免费| 全部免费毛片在线播放网站| 欧美亚洲综合在线| 国产天堂av在线| 不卡视频一二三| 精品少妇无遮挡毛片| 91精品福利| 国产一区二区三区高清| 久久久人成影片一区二区三区在哪下载 | 国产精品欧美久久久| 黄色免费在线看| 精品处破学生在线二十三| 秋霞精品一区二区三区| 国产精品色噜噜| 最新日本中文字幕| 日韩黄色在线观看| 成人在线视频一区二区三区| 亚洲人成精品久久久 | 欧美一区精品| 蜜桃91精品入口| 国产一区二区三区免费在线| 2021国产精品视频| 麻豆tv免费在线观看| 日韩久久免费电影| 国产99对白在线播放| 日韩欧美主播在线| 久草视频福利在线| 日韩国产精品91| 欧美大片免费播放| 国产一区二区亚洲| 国产欧美丝袜| 国产精品视频一区视频二区| 青青草一区二区| 黄色在线观看视频网站| 色噜噜狠狠狠综合曰曰曰| 亚州视频一区二区三区| 日韩丝袜美女视频| 最近中文字幕av| 欧美日韩一区二区三区| 法国伦理少妇愉情| 国产·精品毛片| 亚洲怡红院在线| 日产国产高清一区二区三区| 久久黄色片视频| 狠狠88综合久久久久综合网| 亚洲免费不卡| 欧美日韩激情| 日本高清视频一区二区三区| 精品资源在线| 综合激情成人伊人| 91嫩草在线视频| 不卡福利视频| 性色av一区二区咪爱| 国产激情视频在线| 日韩在线视频线视频免费网站| 免费一级在线观看播放网址| 日韩av在线网| 天天干视频在线| 亚洲国产97在线精品一区| 精品人妻一区二区三区蜜桃| 欧美日韩一本到| 国产成人av免费| 日本道色综合久久| 99久久久无码国产精品免费蜜柚| 欧美日韩精品在线观看| 国产女同在线观看| 亚洲成人动漫一区| 亚欧视频在线观看| 懂色av中文一区二区三区天美| 日韩成人高清视频| 国产亚洲欧美激情| 欧美 日本 国产| 久久国产婷婷国产香蕉| 91精品无人成人www| 日本成人在线电影网| 老司机午夜av| 日本成人在线不卡视频| 天天干天天草天天| 久久国内精品自在自线400部| 怡红院亚洲色图| 国产一区二区在线影院| 日本亚洲一区二区三区| 国产a久久麻豆| 日韩av无码一区二区三区不卡| www.成人网.com| 三上悠亚影音先锋| 国产日韩欧美综合在线| 青青操在线播放| xnxx国产精品| 国产aⅴ激情无码久久久无码| 国产欧美精品在线观看| 欧美性x x x| 一区二区三区四区高清精品免费观看 | 一区二区三区四区视频免费观看| 韩国成人一区| 欧美性aaa| 51国产成人精品午夜福中文下载| 91成人噜噜噜在线播放| 精品无码久久久久久久动漫| 国产剧情一区| 一道本在线观看视频| 91久久久久| 少妇黄色一级片| 国产一区二区在线观看免费 | 91成人短视频| 品久久久久久久久久96高清| 香蕉国产精品| 精品久久一二三| 蜜臀久久99精品久久久画质超高清| 色男人天堂av| 久久人人爽人人爽| 疯狂试爱三2浴室激情视频| 午夜精品久久久| 最近中文字幕在线观看视频| 日韩免费成人网| 国产一级片在线| 亚洲精品成人久久久| 国产系列在线观看| 久久亚洲国产成人| 亚洲美女炮图| 亚洲一区二区三区在线视频 | 最新日韩av| 男女视频在线看| 99久久精品情趣| 日韩在线一卡二卡| 一本久久综合亚洲鲁鲁五月天 | 色播视频在线播放| 欧美日韩一二三区| 欧美视频综合| 久久久久久久久亚洲| 四虎国产精品免费久久5151| 久久久精品国产一区二区三区| 91精品电影| 亚洲精品怡红院| 97久久超碰国产精品| 国产一区二区视频在线观看免费| 欧美日韩亚洲一区二| 精品国产999久久久免费| 在线精品高清中文字幕| 色在线免费观看| 国产精品久久7| 亚洲精品2区| 一区二区三区网址| 久久影院视频免费| 五月婷婷激情网| 欧美成人高清电影在线| 国产精品剧情一区二区在线观看| 国产精品91免费在线| 久久精品色综合| 男人天堂手机在线视频| 国产一区视频网站| 国产传媒免费在线观看| 欧美日韩一区小说| 国产乱理伦片a级在线观看| 992tv成人免费影院| 成人免费直播在线| 99热这里只有精品免费| 国产精品99久久久久久宅男| 成人18视频免费69| 欧美日韩精品系列| 色哟哟免费在线观看| 国产精品在线看| jiujiure精品视频播放| 国产aaaaa毛片| 国产性天天综合网| 波多野结衣毛片| 国产一区二区三区久久精品| 欧美男女交配| 日本一区网站| 蜜臀a∨国产成人精品| 色撸撸在线视频| 欧美日韩国产一区二区三区地区| av中文字幕在线| 国产日韩中文字幕在线| 999精品在线| 中文字幕第10页| 一区二区三区日韩| 欧美一区二区三区成人片在线| 韩国视频理论视频久久| 欧美a级网站| 亚洲精品日韩成人| 久久精品国内一区二区三区| 日韩在线视频免费看| 在线播放91灌醉迷j高跟美女 | 2024亚洲男人天堂| 九九久久婷婷| 黄色永久免费网站| 亚洲人123区| 亚洲av无码乱码在线观看性色 | 一本二本三本亚洲码| 国产精品一级在线| 日韩av黄色片| 国产亚洲欧洲高清| 综合欧美精品| 91精品国产91久久久久麻豆 主演| 99久久精品国产导航| 性高潮视频在线观看| 久久久999精品免费| 大奶在线精品| 另类小说色综合| 亚洲精品国产一区二区三区四区在线| 亚洲男女视频在线观看| 日韩免费高清在线观看| 天天射天天综合网| 国产真实乱人偷精品| 欧美无乱码久久久免费午夜一区| 高清全集视频免费在线| 精品国产综合久久| 美国十次了思思久久精品导航 | 99re在线| 噜噜噜久久亚洲精品国产品小说| 亚洲熟女毛茸茸| 亚洲精品国产拍免费91在线| 欧美xxxx网站| 免费成人深夜夜行视频| 免费成人美女在线观看.| 私库av在线播放| 亚洲欧美激情一区| 婷婷综合国产| 少妇黄色一级片| 亚洲狠狠爱一区二区三区| www黄在线观看| 国产一区二区三区四区五区在线| 麻豆成人免费电影| 久久国产精品免费看|