ReflectASM是一个非常小的高性能反射库.
当 “修改/查询字段”, “调用方法”, “创建实例” 时, 会用ASM字节码技术动态生成一个Access Class. 来避免"java传统反射"的使用.
因为, 他直接使用字节码, 所以他比"java传统反射"要快.
package demo.java.reflectasm;
public class User {
public int id;
public String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package demo.java.reflectasm;
import com.esotericsoftware.reflectasm.ConstructorAccess;
import com.esotericsoftware.reflectasm.FieldAccess;
import com.esotericsoftware.reflectasm.MethodAccess;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectAsmTest {
public static void main(String[] args) throws Exception {
// java reflection
Class<User> clazz = User.class;
Field field = clazz.getField("name");
field.setAccessible(true);
Method method = clazz.getMethod("setName", String.class);
method.setAccessible(true);
// reflection asm
ConstructorAccess<User> ca = ConstructorAccess.get(clazz);
FieldAccess fa = FieldAccess.get(User.class);
MethodAccess ma = MethodAccess.get(User.class);
// use for test
User user = new User();
int times = 100000000;
// case0: common
long startTime0 = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
user = new User();
user.name = "LXQ";
user.setName("liuxianqiang");
}
System.out.println("common : " + (System.currentTimeMillis() - startTime0));
// case1: java reflect
long startTime1 = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
user = clazz.newInstance();
field.set(user, "LXQ");
method.invoke(user, "liuxianqiang");
}
System.out.println("java reflect : " + (System.currentTimeMillis() - startTime1));
// case2: reflectasm use name
long startTime2 = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
user = ca.newInstance();
fa.set(user, "name", "LXQ");
ma.invoke(user, "setName", "liuxianqiang");
}
System.out.println("reflectasm use name : " + (System.currentTimeMillis() - startTime2));
// case3: reflectasm use index
int index1 = fa.getIndex("name");
int index2 = ma.getIndex("setName");
long startTime3 = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
user = ca.newInstance();
fa.set(user, index1, "LXQ");
ma.invoke(user, index2, "liuxianqiang");
}
System.out.println("reflectasm use index : " + (System.currentTimeMillis() - startTime3));
}
}
common : 10
java reflect : 1108
reflectasm use name : 951
reflectasm use index : 8
reflectasm use name 比 reflectasm use index 慢太多
reflectasm use name 内多一步getIndex, 据 “方法名” 遍历查找 “方法索引” .
common 和 reflectasm use index 近乎一致
说明reflectionasm动态生成的AccessClass, 没有带来任何性能的损失.
java reflect 比 common 慢太多
反射终归有性能耗损, 实测如下.
字段/方法: 耗时增加30倍左右
创建对象: 耗时增加100倍左右
ReflectASM包非常小, 共4个核心类
AccessClassLoader
自定义ClassLoader, 加载动态生成的AccessClass
ConstructorAccess
构造器AccessClass, 用于加速创建对象
FieldAccess
字段AccessClass, 用于加速访问字段
MethodAccess
方法AccessClass, 用于加速访问方法
ConstructorAccess, FieldAccess, MethodAccess 都有get(Class type)静态方法,
用ASM字节码技术来动态生成AccessClass子类.
生成的子类, 用arthas dump出来后, 反编译如下.
package demo.java.reflectasm;
import com.esotericsoftware.reflectasm.PublicConstructorAccess;
public class UserConstructorAccess extends PublicConstructorAccess {
public UserConstructorAccess() {
}
public Object newInstance() {
return new User();
}
public Object newInstance(Object var1) {
throw new UnsupportedOperationException("Not an inner class.");
}
}
package demo.java.reflectasm;
import com.esotericsoftware.reflectasm.FieldAccess;
public class UserFieldAccess extends FieldAccess {
public UserFieldAccess() {
}
public Object get(Object var1, int var2) {
switch(var2) {
case 0:
return ((User)var1).id;
case 1:
return ((User)var1).name;
default:
throw new IllegalArgumentException("Field not found: " + var2);
}
}
...
public void set(Object var1, int var2, Object var3) {
switch(var2) {
case 0:
((User)var1).id = (Integer)var3;
return;
case 1:
((User)var1).name = (String)var3;
return;
default:
throw new IllegalArgumentException("Field not found: " + var2);
}
}
...
}
package demo.java.reflectasm;
import com.esotericsoftware.reflectasm.MethodAccess;
public class UserMethodAccess extends MethodAccess {
public Object invoke(Object var1, int var2, Object... var3) {
User var4 = (User)var1;
switch(var2) {
case 0:
return var4.getName();
case 1:
var4.setName((String)var3[0]);
return null;
case 2:
return var4.getId();
case 3:
var4.setId((Integer)var3[0]);
return null;
default:
throw new IllegalArgumentException("Method not found: " + var2);
}
}
public UserMethodAccess() {
}
}