java之靜態代理與動態代理

先看看靜態代理是如何操做的java

定義接口:jvm

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

實際的類:ide

 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 }

代理類:this

 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 }

能夠看到,靜態代理類要求實現與實際類型相同的接口,這個雖然在某些狀況下有使用場景,可是其實擴展起來很麻煩,須要一個個的進行重載,相比之下,動態代理就好多了。spa

動態代理也須要一個代理類,實現特定的接口InvocationHandler:.net

 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幫你作了靜態代理的事情:code

  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對象

相關文章
相關標籤/搜索