先看看靜態代理是如何操做的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對象