当前位置: 首页 > 工具软件 > ReflectASM > 使用案例 >

ReflectASM高性能反射库

景国兴
2023-12-01

ReflectASM高性能反射库

1. 概要

ReflectASM是一个非常小的高性能反射库.

当 “修改/查询字段”, “调用方法”, “创建实例” 时, 会用ASM字节码技术动态生成一个Access Class. 来避免"java传统反射"的使用.

因为, 他直接使用字节码, 所以他比"java传统反射"要快.

2. 示例

2.1 User

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;
    }
}

2.2 ReflectAsmTest

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));
    }
}

2.3运行结果

common : 10
java reflect : 1108
reflectasm use name : 951
reflectasm use index : 8
  1. reflectasm use name 比 reflectasm use index 慢太多

    reflectasm use name 内多一步getIndex, 据 “方法名” 遍历查找 “方法索引” .

  2. common 和 reflectasm use index 近乎一致

    说明reflectionasm动态生成的AccessClass, 没有带来任何性能的损失.

  3. java reflect 比 common 慢太多

    反射终归有性能耗损, 实测如下.

    字段/方法: 耗时增加30倍左右

    创建对象: 耗时增加100倍左右

3. 原理分析

ReflectASM包非常小, 共4个核心类

  1. AccessClassLoader

    自定义ClassLoader, 加载动态生成的AccessClass

  2. ConstructorAccess

    构造器AccessClass, 用于加速创建对象

  3. FieldAccess

    字段AccessClass, 用于加速访问字段

  4. MethodAccess

    方法AccessClass, 用于加速访问方法

ConstructorAccess, FieldAccess, MethodAccess 都有get(Class type)静态方法,

用ASM字节码技术来动态生成AccessClass子类.

生成的子类, 用arthas dump出来后, 反编译如下.

3.1 ConstructorAccess生成子类

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.");
    }
}

3.2 FieldAccess生成子类

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);
        }
    }
    
    ...   
}

3.3 MethodAccess生成子类

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() {
    }
}

4. 参考

 类似资料: