ReflectASM高性能反射库

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. 参考

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值