spring設計模式_代理模式
阿新 • • 發佈:2019-03-19
output boolean ins oca 對象的引用 lec leo interface todo
代理模式應該是Spring核心設計模式之一了
先說下代理模式特性:
1.有代理人和被代理人
2.對於被代理的人來說,這件事情是一定要做的,但是我又不想做,所有就找代理人來做。
3.需要獲取到被代理人的個人資料。
現實中的例子:
黃牛:我需要買票又不想排隊,黃牛拿著我的個人信息代替我買票。。emmmmm不合法,但確實是代理模式
相親: 我需要女朋友又不主動找女朋友,所以媒婆拿著我的個人條件,代替我去找女朋友??????總感覺哪裏怪怪的
GitHub源碼地址:https://github.com/wujiachengSH/WjcProxyDemo
下面我們來舉個栗子看下代碼中的代理是什麽樣子的
咳咳,來個找對象吧
先定義個接口
package com.wjc.proxy; public interface People { String getHeight(); String getSex(); //擇偶標準 void getStandardsOfChoosingSpouse(); }
來個實現類
1 package com.wjc.proxy; 2 3 public class Wjc implements People { 4 5 private String height = "170";6 private String Sex = "男"; 7 8 @Override 9 public String getHeight() { 10 // TODO Auto-generated method stub 11 return height; 12 } 13 14 @Override 15 public String getSex() { 16 // TODO Auto-generated method stub 17 return Sex;18 } 19 20 @Override 21 public void getStandardsOfChoosingSpouse() { 22 // TODO Auto-generated method stub 23 System.out.println("性別男,愛好女"); 24 System.out.println("不想努力了,求富婆包養"); 25 26 } 27 28 29 30 }
來個代理類,代替我調用我自己,傳說中的害羞。。噗
1 package com.wjc.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 public class MatchMaker implements InvocationHandler { 8 // 拿到被代理的對象 9 private People target; 10 11 // 獲取被代理對象 12 public Object getInstance(People target) throws Exception { 13 this.target = target; 14 Class clazz = target.getClass(); 15 return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this); 16 } 17 18 @Override 19 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 20 System.out.println("-------這是一位"+this.target.getSex()+"性-------"); 21 22 method.invoke(this.target, args); 23 System.out.println("找富婆是要付出代價的"); 24 25 return null; 26 } 27 28 }
測試一下
1 package com.wjc.proxy; 2 3 public class Test { 4 public static void main(String[] args) { 5 6 try { 7 People instance = (People) new MatchMaker().getInstance(new Wjc()); 8 instance.getStandardsOfChoosingSpouse(); 9 10 instance.getHeight(); 11 } catch (Exception e) { 12 // TODO Auto-generated catch block 13 e.printStackTrace(); 14 } 15 16 } 17 }
測試結果
通過這個簡單的栗子,看到所謂的代理,其實就是方法增強,嗯,可以拿到對象的所有方法,並且以一定順序來執行。
那麽問題就來了,到底是怎麽實現的呢?
1 package com.wjc.proxy; 2 3 public class Test2 { 4 public static void main(String[] args) { 5 6 try { 7 Wjc wjc = new Wjc(); 8 People instance = (People) new MatchMaker().getInstance(wjc); 9 System.out.println(wjc.getClass()); 10 System.out.println(instance.getClass()); 11 12 } catch (Exception e) { 13 // TODO Auto-generated catch block 14 e.printStackTrace(); 15 } 16 17 } 18 }
執行結果
可以看到已經不是原來的類了
在代理的過程中,會使用反射的技巧,重新生成一個類!
大致代理流程如下所示
//1.拿到被代理對象的引用,然後獲取它的接口 //2.JDK代理重新生成一個類,同時實現我們給的代理對象所實現的接口 //3.把被代理對象的引用也拿到了 //4.重新動態生成一個class字節碼 //5.然後編譯
我們將打印並反編譯出來,看看到底都幹啥了
打印類方法
1 byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class}); 2 FileOutputStream os = new FileOutputStream("E:/$Proxy0.class"); 3 os.write(data); 4 os.close();
通過小工具(luyten) 下載地址:https://github.com/deathmarine/Luyten/releases/tag/v0.5.4
可以看到,創建的類獲取了對象的hashcode,equals,toString和其自有方法來創建了一個新類
所有在使用代理時,此類就是代理人,被他反射的方法的對象就是被代理人
1 import com.wjc.proxy.*; 2 import java.lang.reflect.*; 3 4 public final class $Proxy0 extends Proxy implements People 5 { 6 private static Method m1; 7 private static Method m4; 8 private static Method m2; 9 private static Method m3; 10 private static Method m5; 11 private static Method m0; 12 13 public $Proxy0(final InvocationHandler invocationHandler) { 14 super(invocationHandler); 15 } 16 17 public final boolean equals(final Object o) { 18 try { 19 return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o }); 20 } 21 catch (Error | RuntimeException error) { 22 throw; 23 } 24 catch (Throwable t) { 25 throw new UndeclaredThrowableException(t); 26 } 27 } 28 29 public final String getSex() { 30 try { 31 return (String)super.h.invoke(this, $Proxy0.m4, null); 32 } 33 catch (Error | RuntimeException error) { 34 throw; 35 } 36 catch (Throwable t) { 37 throw new UndeclaredThrowableException(t); 38 } 39 } 40 41 public final String toString() { 42 try { 43 return (String)super.h.invoke(this, $Proxy0.m2, null); 44 } 45 catch (Error | RuntimeException error) { 46 throw; 47 } 48 catch (Throwable t) { 49 throw new UndeclaredThrowableException(t); 50 } 51 } 52 53 public final void getStandardsOfChoosingSpouse() { 54 try { 55 super.h.invoke(this, $Proxy0.m3, null); 56 } 57 catch (Error | RuntimeException error) { 58 throw; 59 } 60 catch (Throwable t) { 61 throw new UndeclaredThrowableException(t); 62 } 63 } 64 65 public final String getHeight() { 66 try { 67 return (String)super.h.invoke(this, $Proxy0.m5, null); 68 } 69 catch (Error | RuntimeException error) { 70 throw; 71 } 72 catch (Throwable t) { 73 throw new UndeclaredThrowableException(t); 74 } 75 } 76 77 public final int hashCode() { 78 try { 79 return (int)super.h.invoke(this, $Proxy0.m0, null); 80 } 81 catch (Error | RuntimeException error) { 82 throw; 83 } 84 catch (Throwable t) { 85 throw new UndeclaredThrowableException(t); 86 } 87 } 88 89 static { 90 try { 91 $Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); 92 $Proxy0.m4 = Class.forName("com.wjc.proxy.People").getMethod("getSex", (Class<?>[])new Class[0]); 93 $Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]); 94 $Proxy0.m3 = Class.forName("com.wjc.proxy.People").getMethod("getStandardsOfChoosingSpouse", (Class<?>[])new Class[0]); 95 $Proxy0.m5 = Class.forName("com.wjc.proxy.People").getMethod("getHeight", (Class<?>[])new Class[0]); 96 $Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]); 97 } 98 catch (NoSuchMethodException ex) { 99 throw new NoSuchMethodError(ex.getMessage()); 100 } 101 catch (ClassNotFoundException ex2) { 102 throw new NoClassDefFoundError(ex2.getMessage()); 103 } 104 } 105 }
spring設計模式_代理模式