ReflectASM详解

概述

ReflectASM是一个很小的java类库,它仅仅有5个类,但是却提供了非常高性能的属性操作、方法调用、构造方法调用,它在底层使用了asm(https://www.ibm.com/developerworks/cn/java/j-lo-asm30/index.html)动态构建出字节码,这相比于反射,直接方法的调用性能高出很多。

可以看下官方给出的性能对比:


image.png

原理分析

以MethodAccess为例,使用方式很简单

MethodAccess access = MethodAccess.get(SomeClass.class);
access.invoke(someObject, "setName", "abc");

通过get方法得到某个类的加强类,直接调用类上的setName完成方法的调用,主要的过程便是在get方法中,它通过asm生成SomeClass的代理类,实现了MethodAccess的invoke方法,方法的内容是生成SomeClass的所有方法的调用index,这样可以通过指定方法名称的方式调用类上的方法。直接调用类上方法的速度肯定要快于反射调用了

复制类

应用中用到从一个类到另外一个类的copy使用ReflectASM性能会好很多,具体的方式如下:
其中对于耗时的get操作增加了缓存,代理类生成一次就够了

public class ReflectAsmManager {
    private static final ConcurrentMap<Class, MethodAccess> localCache = Maps.newConcurrentMap();

    public static MethodAccess get(Class clazz) {
        if(localCache.containsKey(clazz)) {
            return localCache.get(clazz);
        }

        MethodAccess methodAccess = MethodAccess.get(clazz);
        localCache.putIfAbsent(clazz, methodAccess);
        return methodAccess;
    }

    public static <F,T> void copyProperties(F from, T to) {
        MethodAccess fromMethodAccess = get(from.getClass());
        MethodAccess toMethodAccess = get(to.getClass());
        Field[] fromDeclaredFields = from.getClass().getDeclaredFields();
        for(Field field : fromDeclaredFields) {
            String name = field.getName();
            try {
                Object value = fromMethodAccess.invoke(from,  "get" + StringUtils.capitalize(name), null);
                toMethodAccess.invoke(to, "set" + StringUtils.capitalize(name), value);
            } catch (Exception e) {
                // 设置异常,可能会没有对应字段,忽略
            }
        }

    }
}

推荐阅读更多精彩内容