20200114 ASM框架

用了一下BeanUtils.copyPropertie和PropertyUtils.copyProperties()的方法,发现其效率非常低。

原理是通过JDK自带的反射机制动态的去get,set从而去转换我们的类。

使用ASM框架来动态生成

ASM 让我们有能力在运行的过程中动态生成一个新的类并加载和运行它。

ASM是一个通用的 Java 字节码操控和分析框架。它可以用于修改已有的类也可以直接生成类。

主要作用是提高反射的性能。

AOP的实现跟字节码操控密切相关,SpringAOP 是基于动态代理和CGLIB实现的,而CGLIB是基于ASM实现的。所以我们非常有必要学习字节码操控技术。这个领域使用最广泛的框架就是ASM。

 

MethodAccess中传递的是方法的索引,而不是方法名称。

ReflectASM-invoke,高效率java反射机制原理

前段时间在设计公司基于netty的易用框架时,很多地方都用到了反射机制。反射的性能一直是大家有目共睹的诟病,相比于直接调用速度上差了很多。但是在很多地方,作为未知通用判断的时候,不得不调用反射类型来保障代码的复用性和框架的扩展性。所以我们只能想办法优化反射,而不能抵制反射,那么优化方案,这里给大家推荐了ReflectASM。

实际上ReflectASM就是把类的各个方法缓存起来,然后通过case选择,直接调用,因此速度会快上很多。但是它的get方法同样会消耗很大的时间,因此就算是使用ReflectASM的朋友也记得请在启动的时候就初始化get方法计入缓存。

 

   //BeanEntity beanEntityASM = new BeanEntity();
        //使用reflectasm生产User访问类
        //MethodAccess methodAccess = MethodAccess.get(BeanEntity.class);
        //invoke()方法,执行指定的方法,某个对象,方法名,参数;如果参数为空,直接为null;
        //methodAccess.invoke(beanEntityASM, "setName", "张三");
        //String name = (String) methodAccess.invoke(beanEntityASM, "getName", null);
        //System.out.println(name);

        //invoke()方法,执行指定的方法,某个对象,方法名,参数;如果参数为空,直接为null;
        //通过类的Class对象创建对象
        //MethodAccess,返回当前对象的MethodAccess类,主要用于操作当前对象。
        //如何获取一个当前对象的MethodAccess对象?
        //ASM:Java字节码操控框架,可以大幅度提高反射的性能。二进制字节码操作类
        //把类当做一个数组,方法的位置就是索引。MethodAccess的作用:获取某个方法在类中的索引。把类当做数组。
    /**
     * 属性copy类原理
     *
     * @param target 目标
     * @param source 源对象
     */
    public static void copyProperties(Object target, Object source) {
        //获取指定对象的MethodAccess
        MethodAccess targetMethodAccess = methodMap.get(target.getClass());
        if (targetMethodAccess == null) {
            //这行代码是做什么的?
            targetMethodAccess = cache(target);
        }
        MethodAccess sourceMethodAccess = methodMap.get(source.getClass());
        if (sourceMethodAccess == null) {
            sourceMethodAccess = cache(source);
        }

        //获取所有的字段集合
        List<String> fieldList = fieldMap.get(source.getClass());
        for (int i = 0; i < fieldList.size(); i++) {
            String getKey = source.getClass().getName() + "." + "get" + fieldList.get(i);
            String setkey = target.getClass().getName() + "." + "set" + fieldList.get(i);
            Integer setIndex = methodIndexMap.get(setkey);

            if (setIndex != null) {
                int getIndex = methodIndexMap.get(getKey);
                // 参数一需要反射的对象
                // 参数二class.getDeclaredMethods 对应方法的index
                // 参数对三象集合

                //获取原对象的值
                Object obj = sourceMethodAccess.invoke(source, getIndex);

                //把值设置到目标对象的属性上
                targetMethodAccess.invoke(target, setIndex.intValue(), obj);
            }

        }
    }

    // 单例模式
    private static MethodAccess cache(Object orgi) {
        synchronized (orgi.getClass()) {
            MethodAccess methodAccess = MethodAccess.get(orgi.getClass());
            //获取当前对象的公共的字段
            Field[] fields = orgi.getClass().getDeclaredFields();
            //创建集合的时候,指定集合的长度,防止集合扩容。
            ArrayList<String> fieldList = new ArrayList<>(fields.length);
            for (Field field : fields) {
                //如果当前属性的访问修饰符是私有或者静态(//是否是私有的,是否是静态的;私有才会有get和set方法)
                if (Modifier.isPrivate(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())) {
                    //驼峰命名法,首字母大写,获取属性名称
                    String fieldName = StringUtils.capitalize(field.getName());
                    //获取get方法的索引或者说下标
                    int getIndex = methodAccess.getIndex("get" + fieldName);
                    // 获取set方法的下标
                    int setIndex = methodAccess.getIndex("set" + fieldName);
                    //获取当前class的类名,// 将类名get方法名,方法下标注册到map中
                    methodIndexMap.put(orgi.getClass().getName() + "." + "get" + fieldName, getIndex);
                    methodIndexMap.put(orgi.getClass().getName() + "." + "set" + fieldName, setIndex);
                    // 将属性名称放入集合里
                    fieldList.add(fieldName);
                }
            }
            //将类名、属性名称注册到map中
            fieldMap.put(orgi.getClass(), fieldList);
            methodMap.put(orgi.getClass(), methodAccess);
            return methodAccess;
        }
    }

 

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值