在以前的博文《simpleRpc解析-客户端》中,提到了客户端经过JDK动态代理获取Service的代理类,而后经过代理类去执行Service中定义的方法。在动态代理类建立的过程当中,使用的是InvocationHandler的匿名类。java
一开始,我只是简单的从代码角度去查看,觉得在执行Proxy.newProxyInstance()方法的时候会一并执行此匿名类(固然也包括它的invok()方法),而后直接返回代理类,代理类就是一个Service的实现。想法倒也不错,但后来仔细一看,发现匿名类中的invoke(Object object, Method method, Object[] args)方法,怎么看也看不出这几个参数是如何传递进去的!我再想,在建立代理的时候,代码怎么知道我会调用哪一个方法呢?确定不知道啊,那它怎么处理这个Method参数呢?费解ide
再日后看,看到代理类调用service中的方法,又想到以前的invoke()方法已经执行了,这里再调用一次吗?不该该是这样的。后来,我debug此代理类时,看不到什么有效信息,有点迷惑,因此打算再温习下JDK动态代理测试
下面就开始吧this
提供一个接口定义:.net
package com.paic.gof.proxy; public interface Subject { public void rent(); public String hello(String str); }
直接上测试类(使用匿名类方式)debug
package com.paic.gof.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Iterator; import java.util.Properties; import java.util.Set; public class ProxyTest2 { public static void main(String[] args) { /* * 经过Proxy的newProxyInstance方法来建立咱们的代理对象,咱们来看看其三个参数 * handler.getClass().getClassLoader():这里使用handler这个类的ClassLoader对象来加载咱们的代理对象 * realSubject.getClass().getInterfaces():这里为代理对象提供的接口是真实对象所实现的接口, * 表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * handler:这里将这个代理对象关联到了上方的InvocationHandler 这个对象上 */ //下面一句可获得生成的代理类$Proxy0的.class文件,能够反编译查看其内容 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); System.out.println("-----------111---------"); Subject subject = (Subject) Proxy.newProxyInstance( Subject.class.getClassLoader(), new Class<?>[] {Subject.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----------333---------"); System.out.println("method : " + method.getName() + " / args = " + args); return "【invoke-->" + method.getName() + "】"; } }); System.out.println("-----------222---------"); System.out.println(subject.hello("world")); System.out.println("-----------444---------"); System.out.println(subject.toString()); System.out.println("-----------555---------"); System.out.println("class : " + subject.getClass().getName()); System.out.println("super class : " + subject.getClass().getSuperclass()); Class<?>[] interfacess = subject.getClass().getInterfaces(); for(Class ccc : interfacess) { System.out.println("super interface : " + ccc.getName()); } } }
执行结果以下:3d
-----------111--------- -----------222--------- -----------333--------- method : hello / args = [Ljava.lang.Object;@7d4991ad 【invoke-->hello】 -----------444--------- -----------333--------- method : toString / args = null 【invoke-->toString】 -----------555--------- class : com.sun.proxy.$Proxy0 super class : class java.lang.reflect.Proxy super interface : com.paic.gof.proxy.Subject
能够从执行结果结合代码来分析:代理
经过打印出来的数字能够了解代码的执行顺序,能够看到在生成代理类的时候并未执行invoke()方法, 而在代理类对象执行Subject接口定义的方法时,才开始真正的执行!日志
根据打印的日志知道,class : com.sun.proxy.$Proxy0,这就是代理对象subject,下面是它的debug信息:code
信息比较少
再看看它的父类:super class : class java.lang.reflect.Proxy
实现的接口:super interface : com.paic.gof.proxy.Subject
能够了解到,它是一个JDK反射生成的继承了Proxy类并实现给定接口Subject的类
在代码中,经过System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");能够获得它的class信息,生成的.class文件路径以下:
通过反编译获得:
package com.sun.proxy; import com.paic.gof.proxy.Subject; 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 Subject { private static Method m1; private static Method m4; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } public final boolean equals(Object paramObject) throws { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void rent() throws { try { this.h.invoke(this, m4, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String hello(String paramString) throws { try { return (String)this.h.invoke(this, m3, new Object[] { paramString }); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m4 = Class.forName("com.paic.gof.proxy.Subject").getMethod("rent", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.paic.gof.proxy.Subject").getMethod("hello", new Class[] { Class.forName("java.lang.String") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }
从反编译信息中看到它的类定义确实和日志记录是一致的,而且在初始化块中初始化了可被调用的方法m0-m4
至于这个代理对象如何生成的,后续再分析,暂略过
再看下源码的hello()方法,这个方法是Subject接口中定义的:
public final String hello(String paramString) throws { try { return (String)this.h.invoke(this, m3, new Object[] { paramString }); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }
分析下这个方法
在代码中执行System.out.println(subject.hello("world"));
代理类对象subject调用hello()方法,因为subject的定义是接口定义:Subject subject,那么它运行的时候实际是调用其实现类去处理的,这里的实现类就是动态生成的代理类:com.sun.proxy.$Proxy0,而该方法实际调用方式为:
this.h.invoke(this, m3, new Object[] { paramString })
this就表明它自己
m3能够从其初始化块中知道表明hello()
h表明InvocationHandler,从$Proxy0的构造方法能够看到它调用了父类的构造方法(它的父类就是Proxy):super(paramInvocationHandler);
而Proxy中的定义:protected InvocationHandler h;
也就是说,这里实际调用的是Proxy中的变量InvocationHandler,也就是Proxy.newProxyInstance()中的第三个参数,即上面定义的匿名类
理一下:
接口定义的subject对象调用hello()方法,利用多态,实际调用的是代理类的$Proxy0的hello(),而这里的hello()又转而调用其父类的InvocationHandler实现类,也就是调用了匿名类的invoke()方法,在这个方法里实现咱们须要的扩展逻辑!
关于这里的h,经过上面对于代理对象subject的截图中发现,有一个属性h=ProxyTest2$1
并不是InvocationHandler,不知道这里的h是否是同一个对象
再使用非匿名类来测试下:
接口实现类:
package com.paic.gof.proxy; public class RealSubject implements Subject { @Override public void rent() { System.out.println("I want to rent my house"); } @Override public String hello(String str) { System.out.println("hello: " + str); return "hello " + str; } }
InvocationHandler实现类(对比上面的匿名实现类):
package com.paic.gof.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler { // 这个就是咱们要代理的真实对象 private Object subject; // 构造方法,给咱们要代理的真实对象赋初值 public DynamicProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { // 在代理真实对象前咱们能够添加一些本身的操做 System.out.println("before rent house"); System.out.println("subject:" + subject.getClass().getName() + " / Method:" + method); //能够主动调用subject // RealSubject rs = (RealSubject) subject; // rs.hello("hhhhhhh"); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); // 在代理真实对象后咱们也能够添加一些本身的操做 System.out.println("after rent house"); return null; } }
测试类:
package com.paic.gof.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { // 咱们要代理的真实对象 Subject realSubject = new RealSubject(); // 咱们要代理哪一个真实对象,就将该对象传进去,最后是经过该真实对象来调用其方法的 InvocationHandler handler = new DynamicProxy(realSubject); System.out.println("-----------111111111---------"); Subject subject = (Subject) Proxy.newProxyInstance( handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); System.out.println("-----------333---------"); System.out.println(subject.hello("world")); System.out.println("-----------444---------"); System.out.println(subject.getClass().getName()); System.out.println(subject.getClass().getSuperclass()); Class<?>[] interfacess = subject.getClass().getInterfaces(); for(Class ccc : interfacess) { System.out.println(ccc.getName()); } } }
debug查看代理类:
查看这里的h果真就是InvocationHandler实现类,这里尚不清楚为何匿名类测试时显示的是测试类自己,看来要再温习下匿名类了--!
使用匿名类代码量少,简洁,可是不够直观,可读性不如独立实现类简单。。。
好了,啰嗦这么多,大概了解了动态代理的一些概况,后续有时间的话就了解下代理类的生成过程吧
先到这吧,上述阐述不必定正确,有问题请及时留言,一块儿分析进步,谢谢~!