java动态代理
在使用spring框架时,有时候程序报错会看到很多Proxy代理的信息。然而为什么会出现这些信息呢
下面的例子告诉我们,其实我们要执行的实现类是由代理类来执行的:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 /** 8 * 相亲接口 9 */ 10 interface XiangQinInterface { 11 /** 12 * 相亲方法 13 */ 14 public void xiangQin(); 15 } 16 17 /** 18 * 张三相亲实现类 19 */ 20 class ZhangSanXiangQinInterfaceImpl implements XiangQinInterface { 21 public void xiangQin() { 22 System.out.println("张三去相亲,娶个漂亮老婆。"); 23 } 24 } 25 26 /** 27 * 相亲可是一辈子的大事,相亲前要准备一下,打扮得帅气些。 28 */ 29 class ReadyInvocationHandler implements InvocationHandler { 30 // 相亲接口的实现类,也就是张三相亲类 31 private Object zhangSan = null; 32 33 public ReadyInvocationHandler(Object realSubject) { 34 this.zhangSan = realSubject; 35 } 36 37 public Object invoke(Object proxy, Method m, Object[] args) { 38 Object result = null; 39 try { 40 /** 41 * 动态代理类$Proxy0调用xiangQin方法时会调用它自己的xiangQin方法, 42 * 而它自己的xiangQin方法里面调用的是super.h.invoke(this, , 43 * ),也就是父类Proxy的h的invoke方法, 也就是ReadyInvocationHandler类的invoke方法。 44 * 所以,invoke(Object proxy, Method m, Object[] 45 * args)种的proxy实际上就是动态代理类$Proxy0, 46 * 如果你将其强转成XiangQinInterface然后调用它的xiangQin方法 47 * ,然后它就会调用super.h.invoke(this, , ),这样就会死循环。 48 */ 49 /** 50 * 网上关于这里最多问题就是Object proxy放在这里用来做什么呢?这个我也不知道, 51 * 不过至少我们知道它到底是个什么东西,具体做什么用嘛就不得而知了 52 */ 53 System.out.println(proxy.getClass().getSimpleName()); 54 System.out.println("张三相亲前,代理人给他打扮了打扮。"); 55 result = m.invoke(zhangSan, args); 56 } catch (Exception ex) { 57 System.exit(1); 58 } 59 return result; 60 } 61 } 62 63 /** 64 * 张三来到了婚介所(相亲现场),开始相亲。 65 */ 66 public class Dongtaidaili { 67 public static void main(String args[]) { 68 // 先将张三相亲这个相亲的实现类实例化,也就是得到XiangQinInterface接口的一个实例对象 69 XiangQinInterface zhangSan = new ZhangSanXiangQinInterfaceImpl(); 70 /** 71 * 得到ZhangSanXiangQinInterfaceImpl这个类的一个代理类, 72 * 同时为代理类绑定了一个处理类ReadyInvocationHandler。 73 * 听着很绕口,其实就是每次调用ZhangSanXiangQinInterfaceImpl这个子类的xiangQin方法时, 74 * 不是zhangSan这个ZhangSanXiangQinInterfaceImpl类的实例去调用, 75 * 而是这个ZhangSanXiangQinInterfaceImpl的代理类ReadyInvocationHandler去调用它自己的invoke方法 76 * , 这个invoke方法里呢可以调用zhangSan这个实例的xiangQin方法 77 */ 78 /** 79 * 在java种怎样实现动态代理呢 第一步,我们要有一个接口,还要有一个接口的实现类,而这个实现类呢就是我们要代理的对象, 80 * 所谓代理呢也就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。 81 * 第二步,我们要自己写一个在要代理类的方法执行时,能够做额外工作的类,而这个类必须继承InvocationHandler接口, 82 * 为什么要继承它呢?因为代理类的实例在调用实现类的方法的时候,不会调真正的实现类的这个方法, 83 * 而是转而调用这个类的invoke方法(继承时必须实现的方法),在这个方法中你可以调用真正的实现类的这个方法。 84 * 第三步,在要用代理类的实例去调用实现类的方法的时候,写出下面两段代码。 85 */ 86 XiangQinInterface proxy = (XiangQinInterface) Proxy.newProxyInstance(zhangSan 87 .getClass().getClassLoader(), zhangSan.getClass().getInterfaces(), 88 new ReadyInvocationHandler(zhangSan)); 89 proxy.xiangQin(); 90 /** 91 * 这里要解释下中部那段长长的代码的意思,以及具体做了哪些工作? 92 * 第一,根据zhangSan.getClass().getClassLoader()这个要代理类的类加载器和 93 * zhangSan.getClass().getInterfaces()要代理类所实现的所有的接口 94 * 作为参数调用Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces) 95 * 的方法返回代理类的java.lang.Class对象,也就是得到了java动态生成的代理类$Proxy0的Class对象。 96 * 同时,java还让这个动态生成的$Proxy0类实现了要代理类的实现的所有接口,并继承了Proxy接口。 97 * 第二,实例化这个动态生成的$Proxy0类的一个实例,实例化代理类的构造函数为Proxy(InvocationHandler h), 98 * 也就是说要实例化这个动态生成的$Proxy0类,必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类 99 * 方法执行前后做额外工作的类ReadyInvocationHandler。 100 * 这段代码Proxy.newProxyInstance(zhangSan 101 * .getClass().getClassLoader(),zhangSan.getClass().getInterfaces(),new 102 * ReadyInvocationHandler(zhangSan)) 得到的其实是一个类名叫$Proxy0 extends Proxy 103 * implements XiangQinInterface的类。 104 * 第三,将这个$Proxy0类强制转型成XiangQinInterface类型,调用xiangQin方法。 105 */ 106 } 107 }
下面是spring动态代理应用中的一种代理模式JDKProxy,实现了AOP面向切面编程:
可以为每一个服务类添加切向的操作,比如:日志,事务。
1 public class JDKProxy implements InvocationHandler { 2 private Object targetObject;// 代理的目标对象 3 4 public Object createProxyInstance(Object targetObject) { 5 this.targetObject = targetObject; 6 /* 7 * 第一个参数设置代码使用的类装载器,一般采用跟目标类相同的类装载器 8 * 第二个参数设置代理类实现的接口 9 * 第三个参数设置回调对象,当代理对象的方法被调用时,会委派给该参数指定对象的invoke方法 10 */ 11 return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), 12 this.targetObject.getClass().getInterfaces(), this); 13 } 14 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 return method.invoke(this.targetObject, args);// 把方法调用委派给目标对象 17 } 18 }