首先通過(guò)反射獲取待解析對(duì)象的所有 Field,并逐個(gè)讀取去讀取它們的注解,生成一個(gè)從 serializeName 到 Filed 映射 map;解析過(guò)程中,通過(guò)讀取到的 serializeName,到生成的 map 中找到對(duì)應(yīng)的 Filed 信息,然后根據(jù) Filed 的數(shù)據(jù)類型采用特定類型的方式進(jìn)行解析,然后通過(guò)反射方式進(jìn)行賦值 。
因此對(duì)于 Gson 解析耗時(shí)優(yōu)化的核心就是減少反射,這里具體介紹一下抖音中使用到的一些優(yōu)化方案 。
自定義 TypeAdapter 優(yōu)化
通過(guò)對(duì) Gson 的源碼分析,我們知道 Gson 的解析采用的是責(zé)任鏈的形式,如果在 ReflectiveTypeAdapterFactory 之前已經(jīng)有 TypeAdapterFactory 能夠處理某個(gè) Class,那么它是不會(huì)執(zhí)行到 ReflectiveTypeAdapterFactory 的,而 Gson 框架又是支持注入自定義的 TypeAdapterFactory 的,因此我們的一種優(yōu)化方案就是注入一個(gè)自定義的 TypeAdapterFactory 去優(yōu)化這個(gè)解析過(guò)程 。
這個(gè)自定義 TypeAdapterFactory 會(huì)在編譯期為每個(gè)待優(yōu)化的 Class 生成一個(gè)自定義的 TypeAdapter,在這個(gè) TypeAdapter 中會(huì)為 Class 的每個(gè)字段生成相關(guān)的解析代碼,以達(dá)到避免反射的目的 。

生成自定義 TypeAdapter 過(guò)程中的字節(jié)碼處理,我們采用了抖音團(tuán)隊(duì)開源的字節(jié)碼處理框架 Bytex(https://github.com/bytedance/ByteX/blob/master/README_zh.md),具體的實(shí)現(xiàn)過(guò)程如下:
配置待優(yōu)化 Class:在開發(fā)階段,通過(guò)注解、配置文件的方式對(duì)我們需要優(yōu)化的 Class 進(jìn)行加白;收集待優(yōu)化 Class 信息:開始編譯后,我們從配置文件中讀取通過(guò)配置文件配置 Class;在遍歷工程中所有的 class 的 traverse 階段,我們通過(guò) ASM 提供的 ClassVisitor 去讀取通過(guò)注解配置的 Class 。對(duì)于所有需要優(yōu)化的 Class,我們利用 ClassVisitor 的 visitField 方法收集當(dāng)前 Class 的所有 Filed 信息;生成自定義 TypeAdapter 和 TypeAdapterFactory:在 trasform 階段,我們利用收集到的 Class 和 Field 信息生成自定義的 TypeAdapter 類,同時(shí)生成創(chuàng)建這些 TypeAdapter 的自定義 TypeAdapterFactory;public class GsonOptTypeAdapterFactory extends BaseAdapterFactory {
protected BaseAdapter createTypeAdapter(String var1) {
switch(var1.hashCode()) {
case -1939156288:
if (var1.equals("xxx/xxx/gsonopt/model/Model1")) {
return new TypeAdapterForModel1(this.gson);
}
break;
case -1914731121:
if (var1.equals("xxx/xxx/gsonopt/model/Model2")) {
return new TypeAdapterForModel2(this.gson);
}
break;
return null;
}
}
public abstract class TypeAdapterForModel1 extends BaseTypeAdapter {
protected void setFieldValue(String var1, Object var2, JsonReader var3) {
Object var4;
switch(var1.hashCode()) {
case 110371416:
if (var1.equals("field1")) {
var4 = this.gson.getAdapter(String.class).read(var3);
((Model1)var2).field1 = (String)var4;
return true;
}
break;
case 1223751172:
if (var1.equals("filed2")) {
var4 = this.gson.getAdapter(String.class).read(var3);
((Model1)var2).field2 = (String)var4;
return true;
}
}
return false;
}
}
優(yōu)化 ReflectiveTypeAdapterFactory 實(shí)現(xiàn)
上面這種自定義 TypeAdapter 的方式可以對(duì) Gson 的首次解析耗時(shí)優(yōu)化 70%左右,但是這個(gè)方案需要在編譯期增加解析代碼,會(huì)增加包體積,具有一定的局限性,為此我們也嘗試了對(duì) Gson 框架的實(shí)現(xiàn)進(jìn)行了優(yōu)化,為了降低接入成本我們通過(guò)修改字節(jié)碼的方式去修改 ReflectiveTypeAdapterFactory 的實(shí)現(xiàn) 。
原始的 ReflectiveTypeAdapterFactory 在進(jìn)行實(shí)際數(shù)據(jù)解析之前,會(huì)首先去反射 Class 的所有字段信息,再進(jìn)行解析,而在實(shí)際解析過(guò)程中并不是所有的字段都是會(huì)使用到的,以下面的 Person 類為例,在進(jìn)行 Person 解析之前,會(huì)對(duì) Person、Hometown、Job 這三個(gè)類都進(jìn)行解析,但是實(shí)際輸入可能只是簡(jiǎn)單的 name,這種情況下對(duì)于 Hometown、Job 的解析就是完全沒(méi)有必要的,如果 Hometown、Job 類的實(shí)現(xiàn)比較復(fù)雜,這將導(dǎo)致較多不必要的時(shí)間開銷 。
推薦閱讀
- 戰(zhàn)地5多少g內(nèi)存 戰(zhàn)神5多少g-游戲內(nèi)存大小一覽
- 抖音可以分身嗎應(yīng)用vivo 抖音可以分身嗎
- 粉色薔薇是什么梗 抖音粉色薔薇是是什么意思
- 綠色毒刺是什么梗 抖音綠色毒刺是什么意思
- 白色死神是什么梗 抖音白色死神是什么意思
- 開通抖音小店需要多少保證金 開通抖音小店
- 茶花出現(xiàn)大小年的原因,茶花出現(xiàn)大小年的原因有哪些
- 抖音露點(diǎn)合集
- 大小便后請(qǐng)沖水標(biāo)語(yǔ)
- 抖音電腦網(wǎng)頁(yè)版怎么登錄 抖音電腦網(wǎng)頁(yè)版
