java动态代理

2020-03-13  本文已影响0人  7d972d5e05e8

一、 dubbo的SPI代理和Invoker的代理

入口:createAdaptiveExtensionClass -> CtClass.toClass
入口:Proxy getProx -> ClassGenerator.toClass -> CtClass.toClass

二、JDK动态代理效率比Cglib动态代理低的原因

JDK动态代理,方法调用的核心如下:

private static class JdkHandler implements InvocationHandler {

        final Object delegate;

        JdkHandler(Object delegate) {
            this.delegate = delegate;
        }

        @Override
        public Object invoke(Object object, Method method, Object[] objects)
                throws Throwable {
            return method.invoke(delegate, objects);
        }
    }

该invoke方法的核心是使用method.invoke进行反射调用,方法调用并没有直接去类的方法表去搜索。
而Cglib动态代理,方法调用核心如下:

private static class CglibInterceptor implements MethodInterceptor {

        final Object delegate;

        CglibInterceptor(Object delegate) {
            this.delegate = delegate;
        }

        @Override
        public Object intercept(Object object, Method method, Object[] objects,
                MethodProxy methodProxy) throws Throwable {
            return methodProxy.invoke(delegate, objects);
        }
    }

该invoke方法的核心是使用MethodProxy.invoke进行调用,而非反射调用。methodProxy的调用为啥会快于反射调用呢。是因为cglib为被代理类也生成了代理类,然后通过fastClass机制调用。性能可以比肩对象直接调用,稍微有些性能损失,但是要强于反射调用。

fastClass的invoke方法是抽象方法,无法在cglib的源码中找到实现类。为啥呢?因为fastClass是和业务类紧密关联的,cglib没法知道业务类有哪些,只能在运行的时候,通过init里面的helper()方法动态生成fastClass。这个fastClass运行期间,只生成一次,后面再获取可以直接从缓存中拿。而fastClass经过反编译,可以看到源码。

什么是fastClass机制呢?

参考文档:https://blog.csdn.net/yzb808/article/details/88641156

FastClass的实现逻辑,是生成增强类实现invoke方法,invoke方法中,用switch语义将被增强类的所有方法调用枚举出来。用户使用FastClass.invoke方法,传入方法签名和被调用实例,从而达到不使用反射就能实现不确定方法的调用。

FastClass是否真的能比反射调用速度快吗?

参考文档:https://blog.csdn.net/yzb808/article/details/88641156

测试代码如上面的文档中,暂时就不贴了。从测试结果上看,一千万次调用的总耗时,默认情况下,反射执行效率明显优于FastClass。反射操作的时间开销主要存在于获取被反射的方法信息上,默认情况下使用JNI访问器获得该信息。但高版本的JVM在执行反射时引入通胀概念,也即参数-Dsun.reflect.inflationThreshold(默认15)。当一段反射逻辑执行次数超过阈值后,会生成被反射类对应的字节码访问器(sun/reflect/GeneratedMethodAccessor和sun/reflect/DelegatingClassLoader),用于加快反射调用。测试代码中提高通胀阈值后发现反射的执行效率变得很差。

使用FastClass或反射生成字节码访问器都会构造新类占用perm区,网上看到一些oom的例子。但从执行效率方面考量,反射性能更好。
————————————————
学习了!

上一篇 下一篇

猜你喜欢

热点阅读