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 }

 

posted @ 2016-03-10 12:02  何鸿涛  阅读(230)  评论(0编辑  收藏  举报