博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java之静态代理与动态代理
阅读量:4880 次
发布时间:2019-06-11

本文共 7802 字,大约阅读时间需要 26 分钟。

先看看静态代理是如何操作的

定义接口:

1 public interface Person {2     public void sayHello(String content, int age);3     public void sayGoodBye(boolean seeAgin, double time);4 }

实际的类:

1 public class Student implements Person{ 2   3     @Override 4     public void sayHello(String content, int age) { 5         // TODO Auto-generated method stub 6         System.out.println("student say hello" + content + " "+ age); 7     } 8   9     @Override10     public void sayGoodBye(boolean seeAgin, double time) {11         // TODO Auto-generated method stub12         System.out.println("student sayGoodBye " + time + " "+ seeAgin);13     } 14  }

代理类:

1 public class ProxyTest implements Person{ 2      3     private Person o; 4      5     public ProxyTest(Person o){ 6         this.o = o; 7     } 8   9     @Override10     public void sayHello(String content, int age) {11         // TODO Auto-generated method stub12         System.out.println("ProxyTest sayHello begin");13         //在代理类的方法中 间接访问被代理对象的方法14         o.sayHello(content, age);15         System.out.println("ProxyTest sayHello end");16     }17  18     @Override19     public void sayGoodBye(boolean seeAgin, double time) {20         // TODO Auto-generated method stub21         System.out.println("ProxyTest sayHello begin");22         //在代理类的方法中 间接访问被代理对象的方法23         o.sayGoodBye(seeAgin, time);24         System.out.println("ProxyTest sayHello end");25     }26 27 public static void main(String[] args) {28         // TODO Auto-generated method stub29         //s为被代理的对象,某些情况下 我们不希望修改已有的代码,我们采用代理来间接访问30         Student s = new Student();31         //创建代理类对象32         ProxyTest proxy = new ProxyTest(s);33         //调用代理类对象的方法34         proxy.sayHello("welcome to java", 20);35         System.out.println("******");36         //调用代理类对象的方法37         proxy.sayGoodBye(true, 100);38  39     }40  41 }

可以看到,静态代理类要求实现与实际类型相同的接口,这个虽然在某些情况下有使用场景,但是其实扩展起来很麻烦,需要一个个的进行重载,相比之下,动态代理就好多了。

动态代理也需要一个代理类,实现特定的接口InvocationHandler:

1 public class MyInvocationHandler implements InvocationHandler{ 2      3     private Object object; 4      5     public MyInvocationHandler(Object object){ 6         this.object = object; 7     } 8   9     @Override10     public Object invoke(Object proxy, Method method, Object[] args)11             throws Throwable {12         // TODO Auto-generated method stub13         System.out.println("MyInvocationHandler invoke begin");14         System.out.println("proxy: "+ proxy.getClass().getName());15         System.out.println("method: "+ method.getName());16         for(Object o : args){17             System.out.println("arg: "+ o);18         }19         //通过反射调用 被代理类的方法20         method.invoke(object, args);21         System.out.println("MyInvocationHandler invoke end");22         return null;23     }24     25     public static void main(String [] args){26         //创建需要被代理的类27         Student s = new Student();28         //这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常29         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");30         //获得加载被代理类的 类加载器31         ClassLoader loader = Thread.currentThread().getContextClassLoader();32         //指明被代理类实现的接口33         Class
[] interfaces = s.getClass().getInterfaces();34 // 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法35 MyInvocationHandler h = new MyInvocationHandler(s);36 //生成代理类37 Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h);38 //通过代理类调用 被代理类的方法39 proxy.sayHello("yujie.wang", 20);40 proxy.sayGoodBye(true, 100);41 System.out.println("end");42 }43 44 }

这个灵活性就好多了,不用关心自己代理的类到底有多少方法,只用实现一个invoke方法,去做自己想做的事情就好,如果需要根据特定的方法做事情,可能就需要根据method判断了,不如静态代理写在重载方法中感觉好。

那么,java到底是怎么实现动态代理的,不妨反编译一下,拿到的结果如下,可以看到其实是jvm帮你做了静态代理的事情:

1 public final class $Proxy0 extends Proxy implements Person{  2   private static Method m4;  3   private static Method m1;  4   private static Method m0;  5   private static Method m3;  6   private static Method m2;  7     8   public $Proxy0(InvocationHandler paramInvocationHandler)  9     throws  10   { 11     super(paramInvocationHandler); 12   } 13    //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用  14   public final void sayGoodBye(boolean paramBoolean, double paramDouble) 15     throws  16   { 17     try 18     { 19     // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法 20     // m4为代理类通过反射获得的Method 21       this.h.invoke(this, m4, new Object[] { Boolean.valueOf(paramBoolean), Double.valueOf(paramDouble) }); 22       return; 23     } 24     catch (Error|RuntimeException localError) 25     { 26       throw localError; 27     } 28     catch (Throwable localThrowable) 29     { 30       throw new UndeclaredThrowableException(localThrowable); 31     } 32   } 33    34   public final boolean equals(Object paramObject) 35     throws  36   { 37     try 38     { 39       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); 40     } 41     catch (Error|RuntimeException localError) 42     { 43       throw localError; 44     } 45     catch (Throwable localThrowable) 46     { 47       throw new UndeclaredThrowableException(localThrowable); 48     } 49   } 50    51   public final int hashCode() 52     throws  53   { 54     try 55     { 56       return ((Integer)this.h.invoke(this, m0, null)).intValue(); 57     } 58     catch (Error|RuntimeException localError) 59     { 60       throw localError; 61     } 62     catch (Throwable localThrowable) 63     { 64       throw new UndeclaredThrowableException(localThrowable); 65     } 66   } 67   //实现了Person接口的方法,这就是我们调用这个方法Proxy.newProxyInstance必须提供第二个参数的作用  68   public final void sayHello(String paramString, int paramInt) 69     throws  70   { 71     try 72     { 73       // 我们看到通过调用代理类的方法时,最终方法都会委托给InvocationHandler实现类的invoke方法 74       // m4为代理类通过反射获得的Method 75       this.h.invoke(this, m3, new Object[] { paramString, Integer.valueOf(paramInt) }); 76       return; 77     } 78     catch (Error|RuntimeException localError) 79     { 80       throw localError; 81     } 82     catch (Throwable localThrowable) 83     { 84       throw new UndeclaredThrowableException(localThrowable); 85     } 86   } 87    88   public final String toString() 89     throws  90   { 91     try 92     { 93       return (String)this.h.invoke(this, m2, null); 94     } 95     catch (Error|RuntimeException localError) 96     { 97       throw localError; 98     } 99     catch (Throwable localThrowable)100     {101       throw new UndeclaredThrowableException(localThrowable);102     }103   }104   105   static106   {107     try108     {
//代理类通过反射 获得的接口方法Method109 m4 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayGoodBye", new Class[] { Boolean.TYPE, Double.TYPE });110 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });111 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);112 //代理类通过反射 获得的接口方法Method113 m3 = Class.forName("com.yujie.proxy.dynamic.Person").getMethod("sayHello", new Class[] { Class.forName("java.lang.String"), Integer.TYPE });114 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);115 return;116 }117 catch (NoSuchMethodException localNoSuchMethodException)118 {119 throw new NoSuchMethodError(localNoSuchMethodException.getMessage());120 }121 catch (ClassNotFoundException localClassNotFoundException)122 {123 throw new NoClassDefFoundError(localClassNotFoundException.getMessage());124 }125 }126 }

本文参考了https://blog.csdn.net/u011784767/article/details/78281384

转载于:https://www.cnblogs.com/029zz010buct/p/10497605.html

你可能感兴趣的文章
数据库数据的查询----连接查询
查看>>
找不到可安装的ISAM ,asp.net读取数据丢失,解决的一列里有字符与数字的
查看>>
Java学习笔记三(对象的基本思想一)
查看>>
Java程序(文件操作)
查看>>
KMP算法 最小循环节 最大重复次数
查看>>
Proving Equivalences (强连通,缩点)
查看>>
Period (KMP算法 最小循环节 最大重复次数)
查看>>
sgu 103. Traffic Lights
查看>>
poj 3621 Sightseeing Cows
查看>>
hdu 3666 THE MATRIX PROBLEM
查看>>
TopCoder SRM 176 Deranged
查看>>
Javascript中数组与字典(即map)的使用
查看>>
C++不完整的类型
查看>>
memcached(十三)注意事项
查看>>
ITerms2在mac系统下的安装和配色,并和go2shell关联
查看>>
nginx常见面试题1
查看>>
小白用shiro(1)
查看>>
微服务化之无状态化与容器化
查看>>
动态规划LeetCode174地下城游戏
查看>>
Sublime Text 报“Pylinter could not automatically determined the path to lint.py
查看>>