Hello World

吞风吻雨葬落日 欺山赶海踏雪径

0%

ReflectAsm

ReflectASM is a very small Java library that provides high performance reflection by using code generation. An access class is generated to set/get fields, call methods, or create a new instance. The access class uses bytecode rather than Java’s reflection, so it is much faster. It can also access primitive fields via bytecode to avoid boxing.

上面这段应用自ReflectASM的 官网介绍 ,首先ReflectASM非常小,仅仅只有5个类。其次他非常快,依赖了asm来做字节码的生成。
首次关注到ReflectASM是因为一个报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"HSFBizProcessor-DEFAULT-8-thread-1214" Id=48276 BLOCKED on com.xxx.shade.com.esotericsoftware.reflectasm.AccessClassLoader@30da4559 owned by "HSFBizPr
ocessor-DEFAULT-8-thread-1072" Id=48134
at com.xxx.shade.com.esotericsoftware.reflectasm.ConstructorAccess.get(ConstructorAccess.java:54)
- blocked on com.xxx.shade.com.esotericsoftware.reflectasm.AccessClassLoader@30da4559
at com.xxx.shade.com.esotericsoftware.kryo.Kryo$DefaultInstantiatorStrategy.newInstantiatorOf(Kryo.java:1233)
at com.xxx.shade.com.esotericsoftware.kryo.Kryo.newInstantiator(Kryo.java:1078)
at com.xxx.shade.com.esotericsoftware.kryo.Kryo.newInstance(Kryo.java:1087)
at com.xxx.shade.com.esotericsoftware.kryo.serializers.FieldSerializer.createCopy(FieldSerializer.java:665)
at com.xxx.shade.com.esotericsoftware.kryo.serializers.FieldSerializer.copy(FieldSerializer.java:669)
at com.xxx.shade.com.esotericsoftware.kryo.Kryo.copy(Kryo.java:891)
at com.xxx.comm.LocalCache.kryoClone(LocalCache.java:137)
at com.xxx.comm.LocalCache.get(LocalCache.java:235)
at com.xxx.impl.DefaultTairManager.get(DefaultTairManager.java:3388)
at com.xxx.impl.mc.MultiClusterTairManager.get(MultiClusterTairManager.java:716)

上面的线程堆栈中显示了reflectasm的AccessClassLoader有阻塞,发现kryo默认使用了reflectasm作为反序列化后类实例创建的工具。可能还是看重了reflectasm反射创建类实例的效率吧,官网性能对比如下
性能对比

我们看下kryo的使用场景com.esotericsoftware.kryo.Kryo.DefaultInstantiatorStrategy#newInstantiatorOf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public ObjectInstantiator newInstantiatorOf (final Class type) {
if (!Util.IS_ANDROID) {
// Use ReflectASM if the class is not a non-static member class.
Class enclosingType = type.getEnclosingClass();
boolean isNonStaticMemberClass = enclosingType != null && type.isMemberClass()
&& !Modifier.isStatic(type.getModifiers());
if (!isNonStaticMemberClass) {
try {
final ConstructorAccess access = ConstructorAccess.get(type);
return new ObjectInstantiator() {
public Object newInstance () {
try {
return access.newInstance();
} catch (Exception ex) {
throw new KryoException("Error constructing instance of class: " + className(type), ex);
}
}
};
} catch (Exception ignored) {
}
}
}
// Reflection.
try {
Constructor ctor;
try {
ctor = type.getConstructor((Class[])null);
} catch (Exception ex) {
ctor = type.getDeclaredConstructor((Class[])null);
ctor.setAccessible(true);
}
final Constructor constructor = ctor;
return new ObjectInstantiator() {
public Object newInstance () {
try {
return constructor.newInstance();
} catch (Exception ex) {
throw new KryoException("Error constructing instance of class: " + className(type), ex);
}
}
};
} catch (Exception ignored) {
}
if (fallbackStrategy == null) {
if (type.isMemberClass() && !Modifier.isStatic(type.getModifiers()))
throw new KryoException("Class cannot be created (non-static member class): " + className(type));
else {
StringBuilder errorMessageSb = new StringBuilder("Class cannot be created (missing no-arg constructor): " + className(type));
if (type.getSimpleName().equals("")) {
errorMessageSb.append("\n\tThis is an anonymous class, which is not serializable by default in Kryo. Possible solutions: ")
.append("1. Remove uses of anonymous classes, including double brace initialization, from the containing ")
.append("class. This is the safest solution, as anonymous classes don't have predictable names for serialization.")
.append("\n\t2. Register a FieldSerializer for the containing class and call ")
.append( "FieldSerializer#setIgnoreSyntheticFields(false) on it. This is not safe but may be sufficient temporarily. ")
.append("Use at your own risk.");
}
throw new KryoException(errorMessageSb.toString());
}
}
// InstantiatorStrategy.
return fallbackStrategy.newInstantiatorOf(type);
}

首先判断是否是enclosingType,可以参见 https://www.iteye.com/blog/lee-govern-1776046

1
Class enclosingType = type.getEnclosingClass();

确认不是StaticMemberClass后使用了ConstructorAccess来创建类的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
boolean isNonStaticMemberClass = enclosingType != null && type.isMemberClass()
&& !Modifier.isStatic(type.getModifiers());
if (!isNonStaticMemberClass) {
try {
final ConstructorAccess access = ConstructorAccess.get(type);
return new ObjectInstantiator() {
public Object newInstance () {
try {
return access.newInstance();
} catch (Exception ex) {
throw new KryoException("Error constructing instance of class: " + className(type), ex);
}
}
};
} catch (Exception ignored) {
}
}

看来reflectasm的使用还是比较简单的。

maven坐标

1
2
3
4
5
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>reflectasm</artifactId>
<version>1.11.9</version>
</dependency>

常用例子

Method reflection with ReflectASM:

1
2
3
4
SomeClass someObject = ...
MethodAccess access = MethodAccess.get(SomeClass.class);
access.invoke(someObject, "setName", "Awesome McLovin");
String name = (String)access.invoke(someObject, "getName");

Field reflection with ReflectASM:

1
2
3
4
SomeClass someObject = ...
FieldAccess access = FieldAccess.get(SomeClass.class);
access.set(someObject, "name", "Awesome McLovin");
String name = (String)access.get(someObject, "name");

Constructor reflection with ReflectASM:

1
2
ConstructorAccess<SomeClass> access = ConstructorAccess.get(SomeClass.class);
SomeClass someObject = access.newInstance();

其他使用参见 https://github.com/EsotericSoftware/reflectasm