Android 序列化框架 Gson 原理分析,可以优化吗?

前言

大家好,我是小彭。

Gson 是 Google 推出的 Java Json 解析库,具有接入成本低、使用便捷、功能扩展性良好等优点,想必大家都很熟悉了。在这篇文章里,我们将讨论 Gson 的基本用法和以及主要流程的源码分析。


小彭的 Android 交流群 02 群已经建立啦~


学习路线图:


1. Gson 的基本使用

Gradle 依赖

dependencies {    implementation 'com.google.code.gson:gson:2.10'}

1.1 GsonBuilder 配置项

Gson 类是整个库的核心 API,在进行任何序列化或反序列化之前,我们都需要获得一个 Gson 对象。可以直接 new 创建默认配置的 Gson 对象,也可以使用 GsonBuilder 构造者配置 Gson 对象。

事实上,一个 Gson 对象代表一个 Gson 工作环境,不同 Gson 对象之间的配置和缓存都不会复用。 因此,在项目中有必要在 common 层提供一个全局的 Gson 对象,既有利于统一序列化配置,也是 Gson 性能优化的基本保障。

GsonBuilder 使用示例

Gson gson = new GsonBuilder()    // 设置自定义解析(不支持协变)    .registerTypeAdapter(Id.class, new IdTypeAdapter())    // 设置自定义解析(支持协变)    registerTypeHierarchyAdapter(List.class, new MyListTypeAdapter())    // 设置自定义解析(以工厂方式)    .registerTypeAdapterFactory(new IdTypeAdapterFactory())    // 设置日期格式    .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")    // 设置自动切换命名风格规则(默认不切换命名风格)    .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)    // 设置过滤指定字段标识符(默认只过滤 transient 和 static 字段)    .excludeFieldsWithModifiers(Modifier.TRANSIENT | Modifier.STATIC)    // 设置类或字段过滤规则    .setExclusionStrategies(new MyExclusionStrategy1())    // 设置过滤规则(只适用于序列化)    .addSerializationExclusionStrategy(new MyExclusionStrategy2())    // 设置过滤规则(只适用于反序列化)    .addDeserializationExclusionStrategy(new MyExclusionStrategy3())    // 设置序列化版本     .setVersion(1.0)    // 启用非基础类型 Map Key    .enableComplexMapKeySerialization()    // 启用不过滤空值(默认会过滤空值)    .serializeNulls()    // 启用 Json 格式化    .setPrettyPrinting()    .create();

1.2 注解配置

Gson 没有编译时处理,所以注解均是运行时注解。

  • @SerializedName 字段别名: 支持设置多个别名,value 变量在序列化和反序列化时都有效,而 alternate 变量只是在反序列化时做兼容而已;
  • @Expose 字段暴露:默认情况下,一个类中所有字段都会暴露,但使用 @Expose 注解后,只有声明注解的字段才会暴露;注解的 serialize 变量或 deserialize 变量可以声明字段只参与序列化或反序列化,默认都参与。
  • @JsonAdapter 注解: 声明在具体类或字段上,用于更细粒度地设置 TypeAdapter,优先级比 registerTypeAdapter 高;
  • @Since 注解: 声明在具体类或字段上,声明字段的起始序列化版本;
  • @Until 注解: 声明在具体类或字段上,声明字段的终止序列化版本。当字段的序列化版本满足 since ≥ GsonBuilder#setVersion 且 GsonBuilder#setVersion ≤ until 时,才会参与序列化;
  • 1.3JsonSerializer 和 JsonDeserializer自定义解析

    JsonSerializerJsonDeserializer 是 Gson 1.x 版本提供的自定义解析 API,是基于树型结构的解析 API。在解析数据时,它们会将 Json 数据一次性解析为 JsonElement 树型结构。 JsonElement 代表 Json 树上的一个节点,有 4 种具体类型:

    JsonElement描述JsonObject{} 对象JsonArray[] 数组JsonPrimitive基本类型JsonNullnull 值

    1.4 TypeAdapter 自定义解析

    TypeAdapter 是 Gson 2.0 新增的自定义解析 API,是基于流式结构的 API。事实上, JsonSerializer 和 JsonDeserializer 最终也会被构造为 TreeTypeAdapter

    相较之下,JsonSerializer & JsonDeserializer 相对方便,但更费内存。而 TypeAdapter 更节省内存,但不方便。不过,如果需要用到完整数据结构(例如根据 type 字段按照不同类型解析 data),也可以手动解析为树型结构。因此 TypeAdapter 这个 API 的优先级更高。

    TypeAdapterJsonSerializer、JsonDeserializer引入版本2.01.xStream API支持不支持Tree API支持,可以手动转换支持内存占用小比 TypeAdapter 大效率高比 TypeAdapter 低作用范围序列化 + 反序列化序列化 / 反序列化

    1.5 registerTypeAdapter 和 registerTypeHierarchyAdapter 的区别

  • registerTypeAdapter 是不变型的: 只会对注册的类型生效。例如注册 <List.class,TypeAdapter> ,则只会影响 List 类型的字段,但不会影响 ArrayList 类型的字段;
  • registerTypeHierarchyAdapter 是协变型的: 会对注册的类型及其子类生效。例如注册 <List.class,TypeAdapter>,则只会影响 ListArrayList 类型的字段;
  • registerTypeAdapterregisterTypeHierarchyAdapter支持泛型是否支持继承否是


    2. Gson 源码分析

    这一节,我们来分析 Gson 核心流程的工作原理和源码。

    2.1 说一下 Gson 解析的工作过程

    “TypeAdapter” 是 Gson 解析的重要角色,Gson 每次解析一种对象类型,首先需要创建一个 TypeAdapter 对象,之后所有的解析工作都会交给其中的 TypeAdapter#write 和 TypeAdapter#read 方法;

    Java Bean 类型的 TypeAdapter 对象是交给 “ReflectiveTypeAdapterFactory” 创建的。每创建一种类型的 TypeAdapter,都需要递归地使用 “反射” 遍历所有字段,并解析字段上的注解,生成一个 <serializeName – BoundFiled> 的映射表。

  • 在序列化时,首先使用反射获取字段值,再使用字段的 BoundFiled 序列化;
  • 在反序列化时,首先创建对象实例(下文会讨论如何创建),再使用依次使用字段的 BoundField 反序列为字段类型的值,再通过反射为字段赋值。
  • 由于字段值的写入和读取是通过 Field 元数据反射操作的,所以 private 字段也可以操作。

    在构造 Gson 对象时,已经初始化了一系列 TypeAdapter 创建工厂,开发者可以注册自定义的 TypeAdapter:

    Gson.java

    Gson(final Excluder excluder, ...) {    List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();    // built-in type adapters that cannot be overridden    factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);    factories.add(ObjectTypeAdapter.FACTORY);    // 过滤规则    factories.add(excluder);    // 自定义 TypeAdapter    factories.addAll(factoriesToBeAdded);    // 1. 基础类型    factories.add(TypeAdapters.STRING_FACTORY);    factories.add(TypeAdapters.INTEGER_FACTORY);    ...    // 2. 复合类型    // 2.1 列表类型    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));    // 2.2 集合类型    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));    this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);    factories.add(jsonAdapterFactory);    // 2.3 枚举类型    factories.add(TypeAdapters.ENUM_FACTORY);    // 2.4 Java Bean 类型    factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));}

    通过 Gson#getAdapter 查找匹配 TypeAdapter 的方法:

    Gson.java

    // TypeAdapter 缓存映射表 <Type - TypeAdapter>private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>();public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {    // 先从映射表缓存中查找    TypeAdapter<?> cached = typeTokenCache.get(type);    if (cached != null) {        return (TypeAdapter<T>) cached;    }    // 再通过 TypeAdapter 创建工厂创建,并加入映射表缓存中    for (TypeAdapterFactory factory : factories) {        // 从前到后线性扫描创建工厂,找到合适的 TypeAdapter        TypeAdapter<T> candidate = factory.create(this, type);        if (candidate != null) {            // 加入缓存中            typeTokenCache.put(type, candidate);            return candidate;        }    }}

    使用 ReflectiveTypeAdapterFactory 工厂为每种类型创建 TypeAdapter 对象:

    ReflectiveTypeAdapterFactory.java

    // 1. 创建 TypeAdapter 对象@Overridepublic <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {    Class<? super T> raw = type.getRawType();    // 检查是否为 Object 类型    if (!Object.class.isAssignableFrom(raw)) {        return null; // it's a primitive!    }    // 1.1 获取对象构造器(下文分析)    ObjectConstructor<T> constructor = constructorConstructor.get(type);    // 1.2 getBoundFields:解析每个字段的适配器    // 1.3 FieldReflectionAdapter:TypeAdapter 对象(Adapter 类型)    return new FieldReflectionAdapter<T>(constructor, getBoundFields(gson, type, raw));}public static abstract class Adapter<T, A> extends TypeAdapter<T> {    final Map<String, BoundField> boundFields;      // 2. 反序列化过程    @Override     public T read(JsonReader in) {        // 2.1 创建对象        T instance = constructor.construct();        // 2.2 消费 {        in.beginObject();        // 2.3 递归反序列化每个字段        while (in.hasNext()) {              String name = in.nextName();              BoundField field = boundFields.get(name);              if (field == null || !field.deserialized) {                    in.skipValue();              } else {                    // 读取流并设置到 instance 对象中                    readIntoField(in, instance);              }        }        // 2.4 消费 }        in.endObject();        return instance;    }    // 3. 序列化过程    @Override    public void write(JsonWriter out, T value) {        // 3.1 写入 {        out.beginObject();        // 3.2 递归序列化每个字段        for (BoundField boundField : boundFields.values()) {            // 将对象的每个字段写入流中            boundField.write(out, value);        }        // 3.3 写入 }        out.endObject();    }}// -> 1.2 getBoundFields:解析每个字段的适配器private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw, boolean blockInaccessible, boolean isRecord) {    // 1.2.1 映射表    Map<String, BoundField> result = new LinkedHashMap<>();    if (raw.isInterface()) {        return result;    }    ...    // 1.2.2 遍历所有 Field    Field[] fields = raw.getDeclaredFields();    for (Field field : fields) {        // 1.2.2.1 字段过滤        boolean serialize = includeField(field, true);        boolean deserialize = includeField(field, false);        if (!serialize && !deserialize) {           continue;        }        // 1.2.2.2 获取字段的所有别名,第 0 位是主名称        List<String> fieldNames = getFieldNames(field);        // 1.2.2.3 为所有字段别名创建 BoundField 对象        for (int i = 0, size = fieldNames.size(); i < size; ++i) {            String name = fieldNames.get(i);            // serialize = false 这一行说明:序列化时是采用字段的主名称            if (i != 0) serialize = false;            BoundField boundField = createBoundField(context, field, accessor, name, TypeToken.get(fieldType), serialize, deserialize, blockInaccessible);            BoundField replaced = result.put(name, boundField);            if (previous == null) previous = replaced;        }        // 1.2.2.4 存在两个的字段使用相同 serializeName 的冲突        if (previous != null) {            throw new IllegalArgumentException(declaredType + " declares multiple JSON fields named " + previous.name);        }    }    // 1.2.3 返回映射表    return result;}// -> 1.2.2.3 为所有字段别名创建 BoundField 对象private ReflectiveTypeAdapterFactory.BoundField createBoundField(      final Gson context, final Field field, final String name,      final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {    // 基本类型    final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());    // @JsonAdapter 注解    JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);    TypeAdapter<?> mapped = null;    if (annotation != null) {        mapped = jsonAdapterFactory.getTypeAdapter(constructorConstructor, context, fieldType, annotation);    }    final boolean jsonAdapterPresent = mapped != null;    if (mapped == null) mapped = context.getAdapter(fieldType);    final TypeAdapter<?> typeAdapter = mapped;    return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {        @Override         void write(JsonWriter writer, Object value) {            if (!serialized) return;            // 通过反射读取字段值            Object fieldValue = field.get(value);            TypeAdapter t = jsonAdapterPresent ? typeAdapter : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());            // 写出到流            t.write(writer, fieldValue);        }          @Override        void readIntoField(JsonReader reader, Object target) {            // 从流读取            Object fieldValue = typeAdapter.read(reader);            // 通过反射写入字段值            field.set(target, fieldValue);        }    };}

    2.2 List & Set & Map 等容器类型是如何解析的?

  • 1、在预置的容器 TypAdapter 中,会先通过容器类型的 RawType 获取容器构造器,再根据泛型实参 elementType 获取元素类型的 TypeAdapter;
  • 2、在序列化时,先写入 [ 左中括 ,再用元素类型的 TypeAdapter 依次序列化元素对象,再写入 ] 右中括 ;
  • 3、在反序列化时,先创建集合对象,再用元素类型的 TypeAdapter 依次反序列化元素对象;
  • 4、Map 类型需要维护 Key 和 Value 两个 TypeAdapter。
  • CollectionTypeAdapterFactory.java

    // 1. 创建 TypeAdapterpublic <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {    Type type = typeToken.getType();    // 检查是否为列表类型    Class<? super T> rawType = typeToken.getRawType();    if (!Collection.class.isAssignableFrom(rawType)) {        return null;    }    // 1.1 解析元素类型    Type elementType = $Gson$Types.getCollectionElementType(type, rawType);    // 1.2 查找元素类型映射的 TypeAdapterTypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));    // 1.3 解析容器对象的构造器ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);    // 1.4 包装新的 TypeAdapter    TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);}private static final class Adapter<E> extends TypeAdapter<Collection<E>> {    // 2. 反序列化过程    @Override     public Collection<E> read(JsonReader in) {        // 2.1 创建容器对象        Collection<E> collection = constructor.construct();        // 2.2 消费 [        in.beginArray();        // 2.3 使用 1.2 步骤的 TypeAdapter 反序列化每个元素        while (in.hasNext()) {            E instance = elementTypeAdapter.read(in);            collection.add(instance);        }        // 2.4 消费 ]        in.endArray();        return collection;    }    // 3. 序列化过程    @Override     public void write(JsonWriter out, Collection<E> collection) {        // 3.1 写入 [        out.beginArray();        // 3.2 使用 1.2 步骤的 TypeAdapter 序列化每个元素        for (E element : collection) {            elementTypeAdapter.write(out, element);        }        // 3.3 写入 ]        

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

    上一篇 2022年10月15日
    下一篇 2022年10月15日

    相关推荐