java之静态代理与动态代理

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

定义接口:

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     @Override
10     public void sayGoodBye(boolean seeAgin, double time) {
11         // TODO Auto-generated method stub
12         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     @Override
10     public void sayHello(String content, int age) {
11         // TODO Auto-generated method stub
12         System.out.println("ProxyTest sayHello begin");
13         //在代理类的方法中 间接访问被代理对象的方法
14         o.sayHello(content, age);
15         System.out.println("ProxyTest sayHello end");
16     }
17  
18     @Override
19     public void sayGoodBye(boolean seeAgin, double time) {
20         // TODO Auto-generated method stub
21         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 stub
29         //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     @Override
10     public Object invoke(Object proxy, Method method, Object[] args)
11             throws Throwable {
12         // TODO Auto-generated method stub
13         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   static
106   {
107     try
108     {//代理类通过反射 获得的接口方法Method
109       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       //代理类通过反射 获得的接口方法Method
113       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

posted @ 2019-03-08 18:39  boiledwater  阅读(168)  评论(0编辑  收藏  举报