zoukankan      html  css  js  c++  java
  • Java反射机制剖析(四)-深度剖析动态代理原理及总结

    动态代理类原理(示例代码参见java反射机制剖析(三)

    a)  理解上面的动态代理示例流程

    a)  理解上面的动态代理示例流程

     


     

    b)  代理接口实现类源代码剖析

     

    咱们一起来剖析一下代理实现类($Proxy0)的源代码和整个动态代理的流程。

    $Proxy0生成的代码如下:

        import java.lang.reflect.InvocationHandler;  
        import java.lang.reflect.Method;  
        import java.lang.reflect.Proxy;  
        import java.lang.reflect.UndeclaredThrowableException;  
           
        public final class $Proxy0 extends Proxy implements Manager {  
           
        private static Method m1;  
        private static Method m0;  
        private static Method m3;  
        private static Method m2;  
           
        static {  
           try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals",  
              new Class[] { Class.forName("java.lang.Object") });  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
              new Class[0]);  
            m3 = Class.forName("com.ml.test.Manager").getMethod("test",  
              new Class[0]);  
            m2 = Class.forName("java.lang.Object").getMethod("toString",  
              new Class[0]);  
           } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
           } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
           }  
        }  
           
        public $Proxy0(InvocationHandler invocationhandler) {  
           super(invocationhandler);  
        }  
           
        @Override  
        public final boolean equals(Object obj) {  
           try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))  
              .booleanValue();  
           } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
           }  
        }  
           
        @Override  
        public final int hashCode() {  
           try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
           } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
           }  
        }  
           
        public final void test() {  
           try {  
            super.h.invoke(this, m3, null);  
            return;  
           } catch (Error e) {  
           } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
           }  
        }  
           
        @Override  
        public final String toString() {  
           try {  
            return (String) super.h.invoke(this, m2, null);  
           } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
           }  
        }  
        }  

    引入眼帘的是这个代理接口实现类实现了业务类的接口(也就是例子中的UserManager接口),又继承了基类Proxy类;

    接着就是构造函数,在构造方法中把BusinessHandler传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值(这里要看Proxy的构造方法);

    随 后看到的就是这个类重写了Proxy类的Equals、hashCode、toString方法,又实现了业务类接口的方法(即UserManager的 test方法),具体重写和实现都是用到的super.h.invoke(即Proxy.h.invoke)这个方法。

    简单分析完这个代理接口实现类,咱们下面来整体看一下这个动态代理是怎么实现的:

     

    首先客户端初始化了BusinessHandler类,调用这个类的newProxyInstance(new UserManagerImpl())方法来初始化了上面的代理接口实现类;

    接下来代理接口实现类通过构造函数把BusinessHandler传过去(也就是代码中的this),并通过Proxy的构造函数给h赋值;

    随 后再客户端就能实例化出代理接口实现类$Proxy0,我们把它强制转换为业务实现接口(UserManager)类型的(为什么要强制转换,这里非常有 意思,如果不强制转换就会报错,这里很好解释,因为当前的环境根本不会知道这个代理接口实现类$Proxy0既继承Proxy又实现业务实现接口 UserManager,但是强制转换成UserManager它是可以做到的,因为当前环境中就有UserManager。这就是反射的厉害之处,可以 在运行时动态调用任何一个类并可以使用这个类的具体细节。);

    之后当我们调用test方法的时候其实是调用了$Proxy0中的test方法,这个方法的实现是通过Proxy.h的invoke方法实现的(即调用了BusinessHandler.invoke方法);

    之后在调用了Method的invoke方法(这时的参数是this,和args)。

    这样就调用了UserManagerImpl的对应方法,之后返回给客户端。

     

    到此就完成了整个的调用关系。

           

    反射,反射,程序员的快乐

    通 过上篇文章对动态代理进行了深度剖析,现在想起来还感觉非常有意思,这里面其实最根本的机制就是反射机制,运行时动态实例化任何一个类,并且调用它的具体 细节。现在反看动态代理的示例,其实发现这里最关键的还是在就在Proxy.newProxyInstance(..)方法执行时生成了$Proxy0的 内存字节码这一点上,当我们有了内存字节码,我们的反射就会大显威力,这样才有了我们之后的一系列的调用关系。

     

    通过反射机制的分析和动态代理示例的剖析,发现编程是一件多么有意思的事情,以至于我们沉浸其中不能自拔。

     

    最后总结一下:反射,反射,程序员的快乐!

    心得:动态代理生成$Proxy0这个类,说明了用到"反射"这一知识点。

  • 相关阅读:
    python九九乘法表
    js的规范写法ES5(自己以后按照这样写)
    git使用和理解之一(不含分支)
    Javascript中对象的Obeject.defineProperty()方法-------------(ES5/个人理解)
    escape()、encodeURI()、encodeURIComponent()区别详解--zt
    webpack学习(一)
    width:100%以什么为基准的测试
    git status中文文件名编码问题解决
    系统构建基础
    jdk+Tomcat环境搭建
  • 原文地址:https://www.cnblogs.com/crazylqy/p/4253351.html
Copyright © 2011-2022 走看看