动态代理Proxy基本知识点

作者: 未见哥哥 | 来源:发表于2017-09-04 20:58 被阅读123次

    动态代理引入

    代理在我们日常生活中经常出现,例如我们去租房,为了方便我们会去找中介,让他们帮我去找房子,事后我们给他一定比例的中介费就可以了,这种好处就不需要我们自己去奔波租房。

    在程序中也有代理这种思想,当我们想在一个已有的类的方法被调用前和调用后都输出一段日志信息,而我们目前无法修改类内部的结构,但是我们可以生成一个代理对象,通过代理对象去调用目标对象的这些方法,因为目标方法会被代理对象所调用,所以在调用的前后就可以做一些我们先要加入的功能了。

    生成动态代理对象

    Proxy 的介绍

    在 Java 中已经为我们提供了生成动态代理的对象的 API 了,它就是 java.lang.reflect.Proxy

    在 JDK 文档中的介绍如下:

    Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the 
    superclass of all dynamic proxy classes created by those methods. 
    简单翻译:Proxy 提供一些静态方法去创建动态代理字节码对象和动态代理对象,并且 Proxy 是所有动态代理类的父类,这个动态的生成的代理对象是继承了 Proxy 并且实现需要代理的接口方法。
    

    动态生成代理对象的 Class 字节码对象

    通过以下方法可以动态的生成代理类的 Class 字节码对象,这里的参数分别表示:

    • loader 表示加载代理类的类加载器,因为一个 .class 文件要被使用需要通过类加载器进行加载到内存中成为字节码才行。
    • interfaces 代理类需要实现的接口,因为代理对象需要模拟一个跟目标对象一样的功能,因此需要实现目标类实现的接口,这样才有目标类的所有的功能,在代理方法被调用时,代理对象会将该操作分发给 InvocationHandler 去处理。
    • 返回值: 返回一个代理类的字节码对象,这个类是通过 loader 去加载的,并且是通过实现了 interfaces 接口。

    通过这种方式虽然获取了代理类的字节码对象,但是最终获取一个代理对象还是需要通过 Constructor.newInstance(InvocationHandler) 反射来获取。

    public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces)throws IllegalArgumentException
    

    动态生成代理对象

    上面的方式是首先获动态代理的字节码对象,然后再通过 Constructor.newInstance(handler) 的方式来创建动态代理对象,这种感方式需要两步走,稍微麻烦一些。在上面介绍 Proxy 的功能时说过它除了可以动态创建代理对象的字节码对象也可以直接创建爱你动态代理对象。通过以下方法可以动态的生成代理类对象,这里的参数分别表示:

    • loader 表示加载代理类的类加载器;
    • interfaces 代理类需要实现的接口字节码数组;
    • h 表示用于处理目标方法被调用时的回调;
    • 返回值: 返回一个代理对象,这个代理对象是通过 loader 去加载的,并且是通过实现了 interfaces 接口。
    static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    

    InvocationHandler

    JDK 文档对 InvocationHandler 的描述如下:

    InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 
    Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, 
    the method invocation is encoded and dispatched to the invoke method of its invocation handler.
    
    InvocationHandler 是被代理对象所实现的接口,每一个代理对象都有一个 InvocationHandler  成员变量 
    protected InvocationHandler h; 当代理对象的方法被调用时,该方法会将调用分发给它的成员变量 h 去处理。
    

    Proxy的代理方法的调用过程

    在下面的截图就表述的代理方法的调用过程,主要分为 3 步:

    • 用户通过代理对象去调用业务方法,假设为 login 方法 ;
    • 代理对象会将这个操作分发给 InvocationHandler 去处理,它会去调用 invoke 方法;
    • 在 invoke 方法中通过反射去调用目标对象 target 的 login 方法,这样 target 的 login 就真正调用了,同时也可以在在目标方法被调用前后加上 log() 日志的记录。
    Proxy代理方法的调用流程.png

    在下一篇博客会以两个实例来应用动态代理,分别是用户登录和注解框架中@OnClick的实现。

    相关文章

      网友评论

        本文标题:动态代理Proxy基本知识点

        本文链接:https://www.haomeiwen.com/subject/aihejxtx.html