JDK动态代理的invoke方法的第一个参数是什么

2016/11/25 Java

本文由博主原创,转载请注明出处 在知乎回答的一个问题,不过跑题了,但是还是有些价值的,搬到博客,原文链接 java InvocationHandler invoke方法的第一个参数有什么用?

java InvocationHandler invoke方法的第一个参数有什么用? 想知道它有什么用,就必须的先知道它到底是什么… 那InvocationHandler invoke的第一个参数到底是什么呢? 这是 OpenJDK7中InvocationHandler.java接口的注释中的部分:

* @param   proxy the proxy instance that the method was invoked 

看样子是 代理类本身的一个实例.那代理类是什么梗? 其实代理类就是动态代理动态生成的类. 我自己写了一个动态代理,基本都差不多,就不全贴代码了,那么下面在InvocationHandler接口的invoke你增加点内容:

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(proxy.getClass().getName());
        return method.invoke(object,args);
    }

看下输出:\ img

是个:com.sun.proxy.$Proxy0类的实例. 那么这个类究竟是怎么来的呢? 动态代理这个黑盒子又到底做了什么? 生成的这个类为何叫做代理类的实例? 其实动态代理的具体实现(大部分)在ProxyGenerator.java类里.我这里说个大概套路. 其实本质做的事情就是合成你要的代理类,用什么合成,就是你传入的InvocationHandler接口的实现类和要代理的接口.这也是为什么咱们要自己保存要被代理的对象:

public class MyProxy implements InvocationHandler{
    Object object;

    public MyProxy(Object object) {
        this.object = object;
    }

因为生成的代理类就是个空壳子,下面修改下invoke方法.咱们把生成的字节码保存起来

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(proxy.getClass().getName());
        byte[]  b= ProxyGenerator.generateProxyClass(proxy.getClass().getSimpleName(),proxy.getClass().getInterfaces());
        FileOutputStream out = new FileOutputStream("./"+proxy.getClass().getSimpleName()+".class");
        out.write(b);
        out.flush();
        out.close();
        return method.invoke(object,args);
    }

调用代理后,成功拿到$Proxy0.class\ img\ 然后直接反编译,这个东西到底是什么…\ 这是一个实现了我在生成代理传入的接口的class的类..\ 然后看下如何找到这个invoke的

  public final int get(String var1) throws  {
        try {
            return ((Integer)super.h.invoke(this, m4, new Object[]{var1})).intValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

….super.h就是你实现的InvocationHandler具体实例,那么很明显第一个传入的第一个参数就是this喽. this很明显就是生成代理类的实例,也就是楼主想要的知道的类型.

然后invoke里面的method是怎么拿到的? 在生成的代理类的static块你有如下部分:

 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
 m3 =.......
........你接口声明的方法++++.........

jdk动态代理只能代理接口怪我喽?

补充:我好像看跑题了,,,,,,第一个参数有什么用,第一个参数有什么用,第一个参数有什么用第一次 第一个参数卵用都没有,只有我这种闲的蛋疼的人….反编译看看…

======================================= 生成的代理类本身继承了Proxy,因此也一定能拿到传入的代理对象和自己写的Handle

        Field f = proxy.getClass().getSuperclass().getDeclaredField("h");
        f.setAccessible(true);
        System.out.println(f.get(proxy).getClass() + "------" + f.get(proxy));

不过个人觉得纯属智障行为.

不过经过查阅资料,有传说:

(有点个人猜测)因为InvocationHandler是proxy对象的参数,在proxy调用某个目标对象的方法时,可能会采用回调机制调用InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法,这个时候proxy对象则成为形式参数。(这方面的回调在jdk中比较多,例如filenamefilter,比较器,所以猜测了一下 :) )

Search

    Table of Contents