obligatory category_cglib为什么比jdk快

obligatory category_cglib为什么比jdk快在一些系统代码中,随处可见的BeanCopier(源于org.springframework.cglib.beans),它主要用在将PO与DTO互转。一些人在惊叹它的高性能的同时,不曾了解它的实现原理(它不使用的反射)!它基于CGLIB代理,CGLIB(CodeGenerationLibrary)是高效的代码生成包,底层依靠ASM(开源的Java字节码编辑类库)操作字节码实现。JDK动态代…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

在一些系统代码中,随处可见的BeanCopier(源于org.springframework.cglib.beans),它主要用在将PO与DTO互转。一些人在惊叹它的高性能的同时,不曾了解它的实现原理(它不使用的反射)!它基于CGLIB代理,CGLIB(Code Generation Library)是高效的代码生成包,底层依靠ASM(开源的Java字节码编辑类库)操作字节码实现。

JDK动态代理与CGLIB代理

JDK动态代理,其被代理对象必须是某个接口的实现,它在运行期间生成代理对象,其实就是InvocationHandler,这个一点也不陌生。CGLIB代理,实现原理类似于JDK动态代理,也是在运行期间生成代理对象,但针对的被代理对象的要求不再那么严苛(不需要是某个接口的实现)。

多次强调运行期间生成代理对象?

难度还有非运行期间生成代理对象,是的,那就是编译期,之前讲过java冷知识:javac AbstractProcessor

生成后代理类究竟怎样的你知道么

BeanCopier.create会针对源类和目标类生成代理类(此处有反射),而且有一定时间上的消耗,但BeanCopier.copy并未使用反射。它正是巧妙的使用这点,将反射部分(性能差)部分与生成后硬编码分离!

CGLIB通过指定,System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “target\\class”);

如何验证呢?

@Test
public void copyRun() {
    //输出cglib动态代理产生的类
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "target\\class");
    BeanCopier beanCopier = BeanCopier.create(CaiNiao.class, CainiaoDTO.class, false);
    CaiNiao caiNiao = new CaiNiao();
    caiNiao.setSuccess(true);
    caiNiao.setErrorCode("suc");        
    CainiaoDTO cainiaoDTO = new CainiaoDTO();        
    beanCopier.copy(caiNiao,cainiaoDTO,null);
}
/**
* 最终会生成2个class文件
*/
//缓存的key
package org.springframework.cglib.beans;
public class BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a extends KeyFactory implements BeanCopierKey {
    private final String FIELD_0;
    private final String FIELD_1;
    private final boolean FIELD_2;

    public BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a() {
    }

    public Object newInstance(String var1, String var2, boolean var3) {
        return new BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a(var1, var2, var3);
    }

    public BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a(String var1, String var2, boolean var3) {
        this.FIELD_0 = var1;
        this.FIELD_1 = var2;
        this.FIELD_2 = var3;
    }

    public int hashCode() {
        int var10002 = 95401 * 54189869;
        String var10001 = this.FIELD_0;
        var10002 = (var10002 + (var10001 != null ? var10001.hashCode() : 0)) * 54189869;
        var10001 = this.FIELD_1;
        return (var10002 + (var10001 != null ? var10001.hashCode() : 0)) * 54189869 + (this.FIELD_2 ^ 1);
    }

    public boolean equals(Object var1) {
        if (var1 instanceof BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a) {
            String var10000 = this.FIELD_0;
            String var10001 = ((BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a)var1).FIELD_0;
            if (var10001 == null) {
                if (var10000 != null) {
                    return false;
                }
            } else if (var10000 == null || !var10000.equals(var10001)) {
                return false;
            }

            var10000 = this.FIELD_1;
            var10001 = ((BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a)var1).FIELD_1;
            if (var10001 == null) {
                if (var10000 != null) {
                    return false;
                }
            } else if (var10000 == null || !var10000.equals(var10001)) {
                return false;
            }

            if (this.FIELD_2 == ((BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a)var1).FIELD_2) {
                return true;
            }
        }

        return false;
    }

    public String toString() {
        StringBuffer var10000 = new StringBuffer();
        String var10001 = this.FIELD_0;
        var10000 = (var10001 != null ? var10000.append(var10001.toString()) : var10000.append("null")).append(", ");
        var10001 = this.FIELD_1;
        return (var10001 != null ? var10000.append(var10001.toString()) : var10000.append("null")).append(", ").append(this.FIELD_2).toString();
    }
}
//代理目标类
package org.springframework.cglib.empty;
public class Object$$BeanCopierByCGLIB$$990b96d1 extends BeanCopier {
    public Object$$BeanCopierByCGLIB$$990b96d1() {
    }
    //看到了吧,其实接近于硬编码
    public void copy(Object var1, Object var2, Converter var3) {
        CainiaoDTO var10000 = (CainiaoDTO)var2;
        CaiNiao var10001 = (CaiNiao)var1;
        var10000.setErrorCode(((CaiNiao)var1).getErrorCode());
        var10000.setErrorMsg(var10001.getErrorMsg());
        var10000.setSuccess(var10001.getSuccess());
    }
}

JDK动态代理通过启动项中添加:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

//接口
interface Hello {
    String sayHello(String str);
}
@Test
public void jdkProxyRun() {
    /** 输出jdk动态代理产生的类
     * 启动项中添加:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
     * 不能使用System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");原因在于:rt.jar使用AccessController.doPrivileged不能读取项目配置的问题
     */
    Hello hello = (Hello) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[]{Hello.class}, new AbstractInvocationHandler() {
        private Hello hello;
        @Override
        protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
            return method.invoke(hello, args);
        }
    });
}
/**
* 生成后Hello的jdk动态代理
*/
final class $Proxy4 extends Proxy implements Hello {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
    public $Proxy4(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    public final String sayHello(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.kxtx.ebill.test.BeanCopy_test$Hello").getMethod("sayHello", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

JDK动态代理源码

//源于:sun.misc
public class ProxyGenerator {
    //从环境变量中获取配置
    private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
    //最终调用生成代理class文件
    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
        final byte[] var4 = var3.generateClassFile();
        if (saveGeneratedFiles) {//是否生成文件
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");//路径在当前项目下的相对路径
                        }

                        Files.write(var2, var4, new OpenOption[0]);
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }
        return var4;
    }
}

BeanCopier源码

public abstract class BeanCopier {
    //缓存key
    private static final BeanCopier.BeanCopierKey KEY_FACTORY = (BeanCopier.BeanCopierKey)KeyFactory.create(BeanCopier.BeanCopierKey.class);
    //copy方法
    private static final Signature COPY;
    private static final Signature CONVERT;
   static {
        COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER});
        CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)");
    }
    public static BeanCopier create(Class source, Class target, boolean useConverter) {
        BeanCopier.Generator gen = new BeanCopier.Generator();
        gen.setSource(source);
        gen.setTarget(target);
        gen.setUseConverter(useConverter);
        return gen.create();
    }
    //代理类来实现
    public abstract void copy(Object var1, Object var2, Converter var3);

    public static class Generator extends AbstractClassGenerator {
        private static final Source SOURCE = new Source(BeanCopier.class.getName());
        private Class source;
        private Class target;
        private boolean useConverter;

        public Generator() {
            super(SOURCE);
        }
        
        public BeanCopier create() {
            Object key = BeanCopier.KEY_FACTORY.newInstance(this.source.getName(), this.target.getName(), this.useConverter);
            return (BeanCopier)super.create(key);
        }
        //生成BeanCopier的实现类
        public void generateClass(ClassVisitor v) {
            Type sourceType = Type.getType(this.source);
            Type targetType = Type.getType(this.target);
            ClassEmitter ce = new ClassEmitter(v);
            ce.begin_class(46, 1, this.getClassName(), BeanCopier.BEAN_COPIER, (Type[])null, "<generated>");
            EmitUtils.null_constructor(ce);
            //BeanCopier.COPY方法,很熟悉吧
            CodeEmitter e = ce.begin_method(1, BeanCopier.COPY, (Type[])null);
            PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(this.source);
            PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(this.target);
            Map names = new HashMap();

            for(int i = 0; i < getters.length; ++i) {
                names.put(getters[i].getName(), getters[i]);
            }

            Local targetLocal = e.make_local();
            Local sourceLocal = e.make_local();
            if (this.useConverter) {
                e.load_arg(1);
                e.checkcast(targetType);
                e.store_local(targetLocal);
                e.load_arg(0);
                e.checkcast(sourceType);
                e.store_local(sourceLocal);
            } else {
                e.load_arg(1);
                e.checkcast(targetType);
                e.load_arg(0);
                e.checkcast(sourceType);
            }
            //生成硬编码get/set的操作
            for(int i = 0; i < setters.length; ++i) {
                PropertyDescriptor setter = setters[i];
                PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
                if (getter != null) {
                    MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
                    MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
                    if (this.useConverter) {
                        Type setterType = write.getSignature().getArgumentTypes()[0];
                        e.load_local(targetLocal);
                        e.load_arg(2);
                        e.load_local(sourceLocal);
                        e.invoke(read);
                        e.box(read.getSignature().getReturnType());
                        EmitUtils.load_class(e, setterType);
                        e.push(write.getSignature().getName());
                        e.invoke_interface(BeanCopier.CONVERTER, BeanCopier.CONVERT);
                        e.unbox_or_zero(setterType);
                        e.invoke(write);
                    } else if (compatible(getter, setter)) {
                        e.dup2();
                        e.invoke(read);
                        e.invoke(write);
                    }
                }
            }

            e.return_value();
            e.end_method();
            ce.end_class();
        }
}
   

如何区分是cglib还是jdk动态代理生成的类,其实不难,从命名上就可以看出,$Proxy4(jdk动态代理一般都是$开头)和BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a(有继承层级结构和对象的hascode)。obligatory category_cglib为什么比jdk快

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/197040.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 你愿意成为一名全栈设计师吗?

    你愿意成为一名全栈设计师吗?

  • ubuntu 20.04 安装 pycharm 2022.1 .3 及其卸载[通俗易懂]

    ubuntu 20.04 安装 pycharm 2022.1 .3 及其卸载[通俗易懂]官网下载:https://www.jetbrains.com/pycharm/

  • mysql面试题目及答案_docker 面试题

    mysql面试题目及答案_docker 面试题1.事务的基本特征原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的…

  • jmeter正则提取器用法_jmeter字符串截取

    jmeter正则提取器用法_jmeter字符串截取JMeter正则表达式提取器 转自:http://desert3.iteye.com/blog/1394934//提取HTML中隐藏域的值^(.*)$ //提取整个response返回提取MyLabel关联的input的值MyLabel”(.+:create:.+?)”  //提取下面link的href的值JSESSIONI

  • .gho文件检查

    .gho文件检查虽然目前windows10的接受程度越来越广泛,但我接触到的一些非IT人士还是钟爱于windows7系统,本文记录一下在使用ghost还原系统遇到的问题。gho还原失败在还原ghost系统过程中,遇到gho文件损坏,还原失败,导致系统重装卡住,且大部分的PE系统都不能上网,这就比较麻烦了。因为gho文件一直保存于U盘中,可能在平时使用U盘过程中操作不当导致数据出现损坏。为了避免这种事情的再次发生,…

  • 查看linux执行的命令记录_history命令详解

    查看linux执行的命令记录_history命令详解前言我们每次敲打linux命令的时候,有时候想用之前用过的命令,一般情况下,我们都会按↑↓箭头来寻找历史的命令记录,那如果我想用1天前执行的某条命令,难道还要按↑100次?显示这样是不现实的,我们可

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号