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

高效率java反射机制-ReflectASM

阴礼骞
2023-12-01

什么是反射

java反射机制是指在运行状态下,可以动态的获取任意一个类或者对象的属性和方法并动态调用

一、ReflectASM原理解析

ReflectASM 使用字节码生成的方式实现了更为高效的反射机制。执行时会生成一个存取类来 set/get 字段,访问方法或创建实例。一看到 ASM 就能领悟到 ReflectASM 会用字节码生成的方式,而不是依赖于 Java 本身的反射机制来实现的,所以它更快,并且避免了访问原始类型因自动装箱而产生的问题

二、Demo

反射目标

public class Demo {

    private String a;
    private Integer b;

    public String getA() {
        return a;
    }

    public Integer getB() {
        return b;
    }

    public void setA(String a) {
        this.a = a;
    }

    public void setB(Integer b) {
        this.b = b;
    }
}

Main方法

public static void main(String[] args) throws IOException {
	Demo d = new Demo();
	d.setA("asasa");
	d.setB(50);
	Method[] methods = d.getClass().getDeclaredMethods();
	MethodAccess access  = MethodAccess.get(Demo.class);
	for (Method method : methods) {
		int methodIndex = access.getIndex(method.getName(), method.getParameterTypes());
		if (method.getName().startsWith("get")) {
			Object invoke = access.invoke(d, methodIndex);
			System.out.println(invoke);
		}
	}
}

生成的DemoMethodAccess

import java.io.Serializable;

public class DemoMethodAccess extends MethodAccess
  implements Serializable
{
  public Object invoke(Object paramObject, int paramInt, Object[] paramArrayOfObject)
  {
    Demo localDemo = (Demo)paramObject;
    switch (paramInt)
    {
    case 0:
      localDemo.setA((String)paramArrayOfObject[0]);
      return null;
    case 1:
      localDemo.setB((Integer)paramArrayOfObject[0]);
      return null;
    case 2:
      return localDemo.getA();
    case 3:
      return localDemo.getB();
    }
    throw new IllegalArgumentException("Method not found: " + paramInt);
  }
}

通过DemoMethodAccess可知调用invoke方式实际调用的是具体对象的方法因此在使用时会比标准化反射更快更节省时间,在调用方法之前使用了反射、又生成了字节码还进行了新类的加载 这三部一样是很耗时的。如果将从开始到结束的所有时间算进去 其实它相比其他反射并不怎么占优,但如果只生成一次代理类的话其性能就很高了。所以使用这个jar包要注意缓存生成的class对象。尽量少重复生成

三、MethodAccess生成DemoMethodAccess方法(get方法)

读MethodAccess的源码了解到了它的执行过程:

1. 反射Demo.class获取公共非静态方法
2. 用ASM技术动态生成新的继承于MethodAccess的类DemoMethodAccess
3. 在私有变量内记录方法名称参数等信息
4. 在类的invoke方法内实现调用不同的方法

static public MethodAccess get (Class type) {
    ArrayList<Method> methods = new ArrayList<Method>();
    boolean isInterface = type.isInterface();
    if (!isInterface) {
      Class nextClass = type;
      while (nextClass != Object.class) {
        addDeclaredMethodsToList(nextClass, methods);
        nextClass = nextClass.getSuperclass();
      }
    } else {
      recursiveAddInterfaceMethodsToList(type, methods);
    }
   ......
    synchronized (loader) {
        try {
            accessClass = loader.loadClass(accessClassName);
        } catch (ClassNotFoundException ignored) {
            String accessClassNameInternal = accessClassName.replace('.', '/');
            String classNameInternal = className.replace('.', '/');

            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
            MethodVisitor mv;
            //将继承类的路径换成新的(全部替换) 这里换成cn/lsg/codegenerate/MethodAccess
            cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "cn/lsg/codegenerate/MethodAccess",
                    new String[]{"java/io/Serializable"});
         ......
            byte[] data = cw.toByteArray();
            //添加的代码
            FileOutputStream fout;
            try {
                fout = new FileOutputStream("C:/Users/Administrator/Desktop/新建文件夹/"+accessClassName+".class");
                fout.write(data);
                fout.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            accessClass = loader.defineClass(accessClassName, data);
        }
        //添加的代码

    }
    try {
        MethodAccess access = (MethodAccess)accessClass.newInstance();
        access.methodNames = methodNames;
        access.parameterTypes = parameterTypes;
        access.returnTypes = returnTypes;
        return access;
    } catch (Exception ex) {
        throw new RuntimeException("Error constructing method access class: " + accessClassName, ex);
    }
}
 类似资料: