ReflectASM 用法

 

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

使用

pom.xml

        <!-- https://mvnrepository.com/artifact/com.esotericsoftware/reflectasm -->
        <dependency>
            <groupId>com.esotericsoftware</groupId>
            <artifactId>reflectasm</artifactId>
            <version>1.11.9</version>
        </dependency>

以 MethodAccess 为例。


import com.esotericsoftware.reflectasm.MethodAccess;
import org.junit.Test;

public class ReflectasmTest {

    static class SomeClass {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    @Test
    public void methodAccessTest() {

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

        String name = someObject.getName();
        System.out.println("name => "+ name);
    }
}

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

复制类

应用中用到从一个类到另外一个类的 copy 使用 ReflectASM 性能会好很多,具体的方式如下:

其中对于耗时的 get 操作增加了缓存,代理类生成一次就够了。

import com.esotericsoftware.reflectasm.MethodAccess;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.concurrent.ConcurrentMap;

public class ReflectAsmManager {
    private static final Logger logger = LoggerFactory.getLogger(ReflectAsmManager.class);
    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;
    }

    /**
     *
     * @param from F
     * @param to T
     * @param <F> From type
     * @param <T> To type
     */
    public static <F, T> void copyProperties(final F from, final T to) {

        Class<?> fromClass = from.getClass();
        final MethodAccess fma = get(fromClass);
        final MethodAccess tma = get(to.getClass());
        Arrays.stream(fromClass.getDeclaredFields())
                .forEach(field -> {
                    String capitalizeName = StringUtils.capitalize(field.getName());
                    try {
                        Object value = fma.invoke(from, "get" + capitalizeName, null);
                        tma.invoke(to, "set" + capitalizeName, value);
                    } catch (Exception e) {
                        logger.warn("ex => ", e);
                    }
                });

    }
}

参考:

EOF


Power by TeXt.