前言
上文ASM入門篇中除了對ASM
的使用做了介紹,同時也提到ASM
被使用的一些場景,其中有一項就是ASM
被用來代替Java
反射;FastJson
作爲序列化工具,就使用了ASM
來代替反射的使用,提高整體的性能。
序列化
序列化就是將對象轉換成Json
格式的字符串,然後用來持久化或者網絡傳輸;FastJson
提供了接口類ObjectSerializer
:
public interface ObjectSerializer {
void write(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features) throws IOException;
}
- serializer:序列化上下文;
- object:需要轉換爲Json的對象;
- fieldName:父對象字段名稱;
- fieldType:父對象字段類型;
- features:父對象字段序列化features;
ObjectSerializer
的實現類有多種,最常見就是序列化JavaBean
的JavaBeanSerializer
,當然還有一些其他類型的序列化工具類比如:基本類型、日期類型、枚舉類型、一些特殊類型等等;引入的ASM正是對JavaBeanSerializer
的優化,當然要使用ASM優化也是有條件的,滿足條件的情況下會通過ASM生成JavaBeanSerializer
的子類,代替裏面的反射操作;
啓用條件
FastJson提供了ASM的開關,默認開啓狀態,同時在滿足一定的條件下才能使用ASMSerializerFactory
創建ASMSerializer
;
開關
SerializeConfig
中提供了asm開關標識:
private boolean asm = !ASMUtils.IS_ANDROID
默認安卓環境下爲false
,否則爲true
,所有服務端開發一般都是開啓asm的;
JSONType註解
- 如果配置了
serializer
,則使用配置的序列化類:
@JSONType(serializer = JavaBeanSerializer.class)
- 如果配置了
asm
爲false
,則不啓用asm
:
@JSONType(asm = false)
- 如果配置了指定幾種
SerializerFeature
,則不開啓asm
:
@JSONType(serialzeFeatures = {SerializerFeature.WriteNonStringValueAsString,SerializerFeature.WriteEnumUsingToString,SerializerFeature.NotWriteDefaultValue,SerializerFeature.BrowserCompatible})
- 如果配置了
SerializeFilter
,則不開啓asm
:
@JSONType(serialzeFilters = {})
BeanType類信息
如果類修飾符不爲public
,則不開啓asm
,直接使用JavaBeanSerializer
;
如果類名稱字符中包含了<001 || >177 || ==.
的字符,則不啓用asm
;
如果類是接口類則不啓用asm
;
對類屬性的檢查,包括類型,返回值,註解等,不符合的情況下同樣不啓用asm
;
創建ASMSerializer
通過ASM
爲每個JavaBean
生成一個獨立的JavaBeanSerializer
子類,具體步驟如下:
生成類名
創建類之前需要生成一個唯一的名稱:
String className = "ASMSerializer_" + seed.incrementAndGet() + "_" + clazz.getSimpleName()
這裏的seed
是一個AtomicLong
變量;以Person
爲例,則生成的className
爲ASMSerializer_1_Person
;
生成子類
通過ASM的ClassWriter
來生成JavaBeanSerializer
的子類,重寫write
方法,JavaBeanSerializer
中的write
方法會使用反射從JavaBean
中獲取相關信息,而通過ASM生成的ASMSerializer_1_Person
,是針對Person
獨有的序列化工具類,可以看部分代碼:
public class ASMSerializer_1_Person
extends JavaBeanSerializer
implements ObjectSerializer {
public ASMSerializer_1_Person(SerializeBeanInfo serializeBeanInfo) {
super(serializeBeanInfo);
}
public void write(JSONSerializer jSONSerializer, Object object, Object object2, Type type, int n) throws IOException {
if (object == null) {
jSONSerializer.writeNull();
return;
}
SerializeWriter serializeWriter = jSONSerializer.out;
if (!this.writeDirect(jSONSerializer)) {
this.writeNormal(jSONSerializer, object, object2, type, n);
return;
}
if (serializeWriter.isEnabled(32768)) {
this.writeDirectNonContext(jSONSerializer, object, object2, type, n);
return;
}
Person person = (Person)object;
if (this.writeReference(jSONSerializer, object, n)) {
return;
}
if (serializeWriter.isEnabled(0x200000)) {
this.writeAsArray(jSONSerializer, object, object2, type, n);
return;
}
SerialContext serialContext = jSONSerializer.getContext();
jSONSerializer.setContext(serialContext, object, object2, 0);
int n2 = 123;
String string = "email";
String string2 = person.getEmail();
if (string2 == null) {
if (serializeWriter.isEnabled(132)) {
serializeWriter.write(n2);
serializeWriter.writeFieldNameDirect(string);
serializeWriter.writeNull(0, 128);
n2 = 44;
}
} else {
serializeWriter.writeFieldValueStringWithDoubleQuoteCheck((char)n2, string, string2);
n2 = 44;
}
string = "id";
int n3 = person.getId();
serializeWriter.writeFieldValue((char)n2, string, n3);
n2 = 44;
string = "name";
string2 = person.getName();
if (string2 == null) {
if (serializeWriter.isEnabled(132)) {
serializeWriter.write(n2);
serializeWriter.writeFieldNameDirect(string);
serializeWriter.writeNull(0, 128);
n2 = 44;
}
} else {
serializeWriter.writeFieldValueStringWithDoubleQuoteCheck((char)n2, string, string2);
n2 = 44;
}
if (n2 == 123) {
serializeWriter.write(123);
}
serializeWriter.write(125);
jSONSerializer.setContext(serialContext);
}
...省略...
}
因爲是僅是Person
的序列化工具,所有可以發現裏面直接強轉Object
爲Person
,通過直接調用的方式獲取Person
的相關信息,替換了反射的使用,我們知道直接調用的性能比使用反射強很多;
查看源碼
通過ASM生成的JavaBeanSerializer
子類,轉換成字節數組通過類加載直接加載到內存中,如果想查看自動生成的類源碼可以使用如下兩種方式來獲取:
-
添加
Debug
代碼 在ASMSerializerFactory
中找到createJavaBeanSerializer
方法,ASM生成的代碼最終會生成字節數組,部分代碼如下所示:byte[] code = cw.toByteArray(); Class<?> serializerClass = classLoader.defineClassPublic(classNameFull, code, 0, code.length);
在IDEA環境下可以在第二行處加斷點,然後
右擊
斷點,選擇More
,勾選Evaluate and log
,輸入如下代碼:FileOutputStream fileOutputStream = new FileOutputStream(new File("F:/ASMSerializer_1_Person.class")); fileOutputStream.write(code); fileOutputStream.close();
-
使用
arthas
因爲我們已經知道自動生成的類名,可以使用arthas
監控當前進程,然後使用jad命令獲取類源碼:[arthas@17916]$ jad com.alibaba.fastjson.serializer.ASMSerializer_1_Person ClassLoader: +-com.alibaba.fastjson.util.ASMClassLoader@32eebfca +-jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc +-jdk.internal.loader.ClassLoaders$PlatformClassLoader@3688c050 Location: /D:/myRepository/com/alibaba/fastjson/1.2.70/fastjson-1.2.70.jar /* * Decompiled with CFR. * * Could not load the following classes: * com.fastjson.Person */ package com.alibaba.fastjson.serializer; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.JavaBeanSerializer; import com.alibaba.fastjson.serializer.ObjectSerializer; import com.alibaba.fastjson.serializer.SerialContext; import com.alibaba.fastjson.serializer.SerializeBeanInfo; import com.alibaba.fastjson.serializer.SerializeWriter; import com.fastjson.Person; import java.io.IOException; import java.lang.reflect.Type; public class ASMSerializer_1_Person extends JavaBeanSerializer implements ObjectSerializer { public ASMSerializer_1_Person(SerializeBeanInfo serializeBeanInfo) {
注意這裏需要提供類的全名稱:
包名+類名
加載類
通過ASM生成的類信息,不能直接使用,還需要通過類加載加載,這裏通過ASMClassLoader
來加載,加載完之後獲取構造器Constructor
,然後使用newInstance
創建一個JavaBeanSerializer
的子類:
byte[] code = cw.toByteArray();
Class<?> serializerClass = classLoader.defineClassPublic(classNameFull, code, 0, code.length);
Constructor<?> constructor = serializerClass.getConstructor(SerializeBeanInfo.class);
Object instance = constructor.newInstance(beanInfo);
反序列化
將Json
串轉化成對象的過程,FastJson
提供了ObjectDeserializer
接口類:
public interface ObjectDeserializer {
<T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
int getFastMatchToken();
}
- parser:反序列化上下文DefaultJSONParser;
- type:要反序列化的對象的類型;
- fieldName:父對象字段名稱;
同序列化過程,大致分爲以下幾個過程:
生成類名
生成一個業務類的反序列化工具類名:
String className = "FastjsonASMDeserializer_" + seed.incrementAndGet() + "_" + clazz.getSimpleName();
同樣以Person
爲例,那麼生成的className
爲FastjsonASMDeserializer_1_Person
;
生成子類
同樣使用ASM
的ClassWriter
生成JavaBeanDeserializer
的子類,重寫其中的deserialze
方法,部分代碼如下:
public class FastjsonASMDeserializer_1_Person
extends JavaBeanDeserializer {
public char[] name_asm_prefix__ = "\"name\":".toCharArray();
public char[] id_asm_prefix__ = "\"id\":".toCharArray();
public char[] email_asm_prefix__ = "\"email\":".toCharArray();
public ObjectDeserializer name_asm_deser__;
public ObjectDeserializer email_asm_deser__;
public FastjsonASMDeserializer_1_Person(ParserConfig parserConfig, JavaBeanInfo javaBeanInfo) {
super(parserConfig, javaBeanInfo);
}
public Object createInstance(DefaultJSONParser defaultJSONParser, Type type) {
return new Person();
}
public Object deserialze(DefaultJSONParser defaultJSONParser, Type type, Object object, int n) {
block18: {
String string;
int n2;
String string2;
int n3;
Person person;
block20: {
ParseContext parseContext;
ParseContext parseContext2;
block19: {
block22: {
JSONLexerBase jSONLexerBase;
block24: {
int n4;
int n5;
block23: {
block21: {
String string3;
String string4;
jSONLexerBase = (JSONLexerBase)defaultJSONParser.lexer;
if (jSONLexerBase.token() == 14 && jSONLexerBase.isEnabled(n, 8192)) {
return this.deserialzeArrayMapping(defaultJSONParser, type, object, null);
}
if (!jSONLexerBase.isEnabled(512) || jSONLexerBase.scanType("com.fastjson.Person") == -1) break block18;
ParseContext parseContext3 = defaultJSONParser.getContext();
n5 = 0;
person = new Person();
parseContext2 = defaultJSONParser.getContext();
parseContext = defaultJSONParser.setContext(parseContext2, person, object);
if (jSONLexerBase.matchStat == 4) break block19;
n4 = 0;
n3 = 0;
boolean bl = jSONLexerBase.isEnabled(4096);
if (bl) {
n3 |= 1;
string4 = jSONLexerBase.stringDefaultValue();
} else {
string4 = null;
}
string2 = string4;
n2 = 0;
if (bl) {
n3 |= 4;
string3 = jSONLexerBase.stringDefaultValue();
} else {
string3 = null;
}
string = string3;
string2 = jSONLexerBase.scanFieldString(this.email_asm_prefix__);
if (jSONLexerBase.matchStat > 0) {
n3 |= 1;
}
if ((n4 = jSONLexerBase.matchStat) == -1) break block20;
if (jSONLexerBase.matchStat <= 0) break block21;
++n5;
if (jSONLexerBase.matchStat == 4) break block22;
}
n2 = jSONLexerBase.scanFieldInt(this.id_asm_prefix__);
if (jSONLexerBase.matchStat > 0) {
n3 |= 2;
}
if ((n4 = jSONLexerBase.matchStat) == -1) break block20;
if (jSONLexerBase.matchStat <= 0) break block23;
++n5;
if (jSONLexerBase.matchStat == 4) break block22;
}
string = jSONLexerBase.scanFieldString(this.name_asm_prefix__);
if (jSONLexerBase.matchStat > 0) {
n3 |= 4;
}
if ((n4 = jSONLexerBase.matchStat) == -1) break block20;
if (jSONLexerBase.matchStat <= 0) break block24;
++n5;
if (jSONLexerBase.matchStat == 4) break block22;
}
if (jSONLexerBase.matchStat != 4) break block20;
}
if ((n3 & 1) != 0) {
person.setEmail(string2);
}
if ((n3 & 2) != 0) {
person.setId(n2);
}
if ((n3 & 4) != 0) {
person.setName(string);
}
}
defaultJSONParser.setContext(parseContext2);
if (parseContext != null) {
parseContext.object = person;
}
return person;
}
if ((n3 & 1) != 0) {
person.setEmail(string2);
}
if ((n3 & 2) != 0) {
person.setId(n2);
}
if ((n3 & 4) != 0) {
person.setName(string);
}
return (Person)this.parseRest(defaultJSONParser, type, object, person, n, new int[]{n3});
}
return super.deserialze(defaultJSONParser, type, object, n);
}
...省略...
}
可以發現同樣使用具體的業務類,代替了在JavaBeanDeserializer
使用反射操作;同樣最後需要對該類信息進行加載,然後通過構造器實例化具體業務對象。
總結
本文使用ASM
代替反射只是衆多使用場景的一種,在FastJson
中只用了ASM
的生成類功能;ASM
更強的的功能是它的轉換功能,對現有類進行改造,生成新的類從而對現有類進行功能增強,當然加載的過程也不是簡單的使用類加載器就行了,這時候配合Java Agent
來實現熱更新;其實代替反射除了使用ASM
,在Protobuf
中也提供了一種方法,在研發階段就把所有的業務序列化反序列化操作都準備好,是一種靜態的處理方式,而ASM
這種動態生成的方式更加人性化。